Repository navigation
Android profiles never include CPU/memory measurements: endAndCollect is always passed null #6887
Description
What React Native libraries do you use?
Expo Router
Are you using sentry.io or on-premise?
sentry.io (SaaS)
@sentry/react-native SDK Version
8.30.0 (latest; also present on main)
Platform
Android
Steps to Reproduce
- Enable profiling on Android with Hermes:
profilesSampleRate: 1(defaulthermesProfilingIntegration,platformProfilers: true). - Navigate a few screens so profiled transactions are sent.
- Fetch a profile via
GET /api/0/projects/{org}/{project}/profiling/raw_profiles/{profile_id}/.
Expected Result
Android profiles include cpu_usage and memory_footprint measurements, as the 8.14 changelog entry "Add memory, CPU, and frame measurements to Android profiling" (#6250) describes, and as iOS profiles already do.
Actual Result
Android profiles carry no cpu_usage / memory_footprint. The native Android profile (method trace) and the Hermes profile are present, but measurements is absent.
The cause is in RNSentryModuleImpl.stopProfiling() (and invalidate()):
end = profiler.endAndCollect(false, null);The second argument of AndroidProfiler.endAndCollect(boolean, List<PerformanceCollectionData>) is where AndroidProfiler gets the CPU and memory samples it turns into those measurements. It's always null, so they can never be produced. #6250 forwards end.measurementsMap to JS but doesn't start any performance collection, so only frame measurements can appear (and only when slow or frozen frames happen).
Suggested fix
Start the SDK's composite performance collector alongside the Android profiler and pass its data to endAndCollect. SentryAndroid already registers AndroidCpuCollector and AndroidMemoryCollector and sets a DefaultCompositePerformanceCollector, which samples on its own timer thread, so this adds no JS-thread work. We're running this as a local patch-package patch against 8.30.0:
+ private final AtomicReference<String> performanceCollectionId = new AtomicReference<>();
@@ startProfiling
if (profiler != null) {
profiler.start();
+ startPerformanceCollection();
}
@@ stopProfiling
- end = profiler.endAndCollect(false, null);
+ end = profiler.endAndCollect(false, stopPerformanceCollection());
@@ invalidate
- final AndroidProfiler.ProfileEndData end = profiler.endAndCollect(false, null);
+ final AndroidProfiler.ProfileEndData end =
+ profiler.endAndCollect(false, stopPerformanceCollection());
@@
+ private void startPerformanceCollection() {
+ try {
+ final String id = UUID.randomUUID().toString();
+ ScopesAdapter.getInstance().getOptions().getCompositePerformanceCollector().start(id);
+ performanceCollectionId.set(id);
+ } catch (Throwable e) { // NOPMD - Measurements are best-effort; the profile still records.
+ logger.log(SentryLevel.WARNING, "Failed to start profile performance collection: " + e);
+ }
+ }
+
+ private @Nullable List<PerformanceCollectionData> stopPerformanceCollection() {
+ final String id = performanceCollectionId.getAndSet(null);
+ if (id == null) {
+ return null;
+ }
+ try {
+ return ScopesAdapter.getInstance().getOptions().getCompositePerformanceCollector().stop(id);
+ } catch (Throwable e) { // NOPMD - Measurements are best-effort; the profile still records.
+ logger.log(SentryLevel.WARNING, "Failed to stop profile performance collection: " + e);
+ return null;
+ }
+ }With this, raw Android profiles include cpu_usage, memory_footprint and memory_native_footprint (e.g. 17–35 samples per screen-load profile on an API 36 emulator), and nothing else in the profile changes. Happy to open a PR if that's useful.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsNo status
Activity
linear-code commentedon Oct 14, 2026
RN-825
antonis commentedon Oct 15, 2026
Thank you for reporting 🙇 We will investigate this and iterate back!
github-actions commentedon Oct 15, 2026
A PR closing this issue has just been released 🚀
This issue was referenced by PR #6891, which was included in the 8.31.0 release.