From f61f02b37e4dd7fcb273f7d09b2ffab4d00879c4 Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Tue, 30 Sep 2025 14:18:02 +0200 Subject: [PATCH 1/7] Fix condition in RNPerformance.removeListener --- .../src/main/java/com/oblador/performance/RNPerformance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/RNPerformance.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/RNPerformance.java index 4d6223b..2f6643b 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/RNPerformance.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/RNPerformance.java @@ -43,7 +43,7 @@ protected void addListener(MarkerListener listener) { @DoNotStrip protected void removeListener(MarkerListener listener) { - if (!sListeners.contains(listener)) { + if (sListeners.contains(listener)) { sListeners.remove(listener); } } From 83cef16de2e878846f7e987547d6ae4f8f38ebeb Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Tue, 30 Sep 2025 14:20:57 +0200 Subject: [PATCH 2/7] Fix ReactMarker listener leak --- .../performance/PerformanceModule.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java index 4a187bb..eb003e5 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java @@ -24,6 +24,18 @@ public class PerformanceModule extends ReactContextBaseJavaModule implements Tur private static boolean eventsBuffered = true; private static final Queue markBuffer = new ConcurrentLinkedQueue<>(); private static boolean didEmit = false; + private final ReactMarker.MarkerListener markerListener = (name, tag, instanceKey) -> { + switch (name) { + case CONTENT_APPEARED: + eventsBuffered = false; + emitNativeStartupTime(); + emitBufferedMarks(); + break; + case RELOAD: + eventsBuffered = true; + break; + } + }; public PerformanceModule(@NonNull final ReactApplicationContext reactContext) { super(reactContext); @@ -125,18 +137,7 @@ private void emitNativeStartupTime() { private void setupMarkerListener() { ReactMarker.addListener( - (name, tag, instanceKey) -> { - switch (name) { - case CONTENT_APPEARED: - eventsBuffered = false; - emitNativeStartupTime(); - emitBufferedMarks(); - break; - case RELOAD: - eventsBuffered = true; - break; - } - } + markerListener ); } @@ -218,6 +219,7 @@ public void logMarker(PerformanceEntry entry) { public void onCatalystInstanceDestroy() { super.onCatalystInstanceDestroy(); RNPerformance.getInstance().removeListener(this); + ReactMarker.removeListener(markerListener); } // Fix new arch runtime error From cf3542d0478b0e2252a1cdf979a4c61521508c2f Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Tue, 30 Sep 2025 14:22:02 +0200 Subject: [PATCH 3/7] Use invalidate instead of deprecated onCatalystInstanceDestroyed and add missing method from spec --- .../performance/PerformanceModule.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java index eb003e5..57ba4aa 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java @@ -130,6 +130,16 @@ public String getName() { return PERFORMANCE_MODULE; } + @Override + public void addListener(String eventName) { + + } + + @Override + public void removeListeners(double count) { + + } + private void emitNativeStartupTime() { safelyEmitMark(new PerformanceMark("nativeLaunchStart", StartTimeProvider.getStartTime())); safelyEmitMark(new PerformanceMark("nativeLaunchEnd", StartTimeProvider.getEndTime())); @@ -216,14 +226,9 @@ public void logMarker(PerformanceEntry entry) { } @Override - public void onCatalystInstanceDestroy() { - super.onCatalystInstanceDestroy(); + public void invalidate() { + super.invalidate(); RNPerformance.getInstance().removeListener(this); ReactMarker.removeListener(markerListener); } - - // Fix new arch runtime error - public void addListener(String eventName) { - - } } From 1afbb377cb26043e7bd69f716632c9f8a6575fb7 Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Fri, 10 Oct 2025 16:49:03 +0200 Subject: [PATCH 4/7] Prevent leaking listener when getPackages is called multiple times --- .../performance/PerformanceModule.java | 112 +++++++++--------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java index 57ba4aa..1f63e89 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java @@ -24,7 +24,51 @@ public class PerformanceModule extends ReactContextBaseJavaModule implements Tur private static boolean eventsBuffered = true; private static final Queue markBuffer = new ConcurrentLinkedQueue<>(); private static boolean didEmit = false; - private final ReactMarker.MarkerListener markerListener = (name, tag, instanceKey) -> { + + private static final ReactMarker.MarkerListener startupMarkerListener = (name, tag, instanceKey) -> { + switch (name) { + case RELOAD: + clearMarkBuffer(); + addMark(new PerformanceMark(BRIDGE_SETUP_START, SystemClock.uptimeMillis())); + break; + case ATTACH_MEASURED_ROOT_VIEWS_END: + case ATTACH_MEASURED_ROOT_VIEWS_START: + case BUILD_NATIVE_MODULE_REGISTRY_END: + case BUILD_NATIVE_MODULE_REGISTRY_START: + case CONTENT_APPEARED: + case CREATE_CATALYST_INSTANCE_END: + case CREATE_CATALYST_INSTANCE_START: + case CREATE_REACT_CONTEXT_END: + case CREATE_REACT_CONTEXT_START: + case CREATE_UI_MANAGER_MODULE_CONSTANTS_END: + case CREATE_UI_MANAGER_MODULE_CONSTANTS_START: + case CREATE_UI_MANAGER_MODULE_END: + case CREATE_UI_MANAGER_MODULE_START: + case CREATE_VIEW_MANAGERS_END: + case CREATE_VIEW_MANAGERS_START: + case DOWNLOAD_END: + case DOWNLOAD_START: + case LOAD_REACT_NATIVE_SO_FILE_END: + case LOAD_REACT_NATIVE_SO_FILE_START: + case PRE_RUN_JS_BUNDLE_START: + case PRE_SETUP_REACT_CONTEXT_END: + case PRE_SETUP_REACT_CONTEXT_START: + case PROCESS_CORE_REACT_PACKAGE_END: + case PROCESS_CORE_REACT_PACKAGE_START: + case REACT_CONTEXT_THREAD_END: + case REACT_CONTEXT_THREAD_START: + case RUN_JS_BUNDLE_END: + case RUN_JS_BUNDLE_START: + case SETUP_REACT_CONTEXT_END: + case SETUP_REACT_CONTEXT_START: + case VM_INIT: + long startTime = SystemClock.uptimeMillis(); + addMark(new PerformanceMark(getMarkName(name), startTime)); + break; + } + }; + + private final ReactMarker.MarkerListener contentAppearedListener = (name, tag, instanceKey) -> { switch (name) { case CONTENT_APPEARED: eventsBuffered = false; @@ -43,6 +87,12 @@ public PerformanceModule(@NonNull final ReactApplicationContext reactContext) { setupNativeMarkerListener(); } + private void setupMarkerListener() { + ReactMarker.addListener( + contentAppearedListener + ); + } + private void setupNativeMarkerListener() { RNPerformance.getInstance().addListener(this); } @@ -50,51 +100,13 @@ private void setupNativeMarkerListener() { // Need to set up the marker listener before the react module is initialized // to capture all events public static void setupListener() { - ReactMarker.addListener( - (name, tag, instanceKey) -> { - switch (name) { - case RELOAD: - clearMarkBuffer(); - addMark(new PerformanceMark(BRIDGE_SETUP_START, SystemClock.uptimeMillis())); - break; - case ATTACH_MEASURED_ROOT_VIEWS_END: - case ATTACH_MEASURED_ROOT_VIEWS_START: - case BUILD_NATIVE_MODULE_REGISTRY_END: - case BUILD_NATIVE_MODULE_REGISTRY_START: - case CONTENT_APPEARED: - case CREATE_CATALYST_INSTANCE_END: - case CREATE_CATALYST_INSTANCE_START: - case CREATE_REACT_CONTEXT_END: - case CREATE_REACT_CONTEXT_START: - case CREATE_UI_MANAGER_MODULE_CONSTANTS_END: - case CREATE_UI_MANAGER_MODULE_CONSTANTS_START: - case CREATE_UI_MANAGER_MODULE_END: - case CREATE_UI_MANAGER_MODULE_START: - case CREATE_VIEW_MANAGERS_END: - case CREATE_VIEW_MANAGERS_START: - case DOWNLOAD_END: - case DOWNLOAD_START: - case LOAD_REACT_NATIVE_SO_FILE_END: - case LOAD_REACT_NATIVE_SO_FILE_START: - case PRE_RUN_JS_BUNDLE_START: - case PRE_SETUP_REACT_CONTEXT_END: - case PRE_SETUP_REACT_CONTEXT_START: - case PROCESS_CORE_REACT_PACKAGE_END: - case PROCESS_CORE_REACT_PACKAGE_START: - case REACT_CONTEXT_THREAD_END: - case REACT_CONTEXT_THREAD_START: - case RUN_JS_BUNDLE_END: - case RUN_JS_BUNDLE_START: - case SETUP_REACT_CONTEXT_END: - case SETUP_REACT_CONTEXT_START: - case VM_INIT: - long startTime = SystemClock.uptimeMillis(); - addMark(new PerformanceMark(getMarkName(name), startTime)); - break; - - } - } - ); + ReactMarker.addListener(startupMarkerListener); + } + + public static void cleanup() { + markBuffer.clear(); + eventsBuffered = true; + didEmit = false; } private static void clearMarkBuffer() { @@ -145,12 +157,6 @@ private void emitNativeStartupTime() { safelyEmitMark(new PerformanceMark("nativeLaunchEnd", StartTimeProvider.getEndTime())); } - private void setupMarkerListener() { - ReactMarker.addListener( - markerListener - ); - } - private void safelyEmitMark(PerformanceEntry entry) { if (eventsBuffered) { addMark(entry); @@ -229,6 +235,6 @@ public void logMarker(PerformanceEntry entry) { public void invalidate() { super.invalidate(); RNPerformance.getInstance().removeListener(this); - ReactMarker.removeListener(markerListener); + ReactMarker.removeListener(contentAppearedListener); } } From a12516de3f60a210e7815cc6aeb3052fdf1e27a9 Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Fri, 10 Oct 2025 17:09:04 +0200 Subject: [PATCH 5/7] Remove unused method --- .../com/oblador/performance/PerformanceModule.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java index 1f63e89..58847fb 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java @@ -103,12 +103,6 @@ public static void setupListener() { ReactMarker.addListener(startupMarkerListener); } - public static void cleanup() { - markBuffer.clear(); - eventsBuffered = true; - didEmit = false; - } - private static void clearMarkBuffer() { RNPerformance.getInstance().clearEphermalEntries(); @@ -144,12 +138,12 @@ public String getName() { @Override public void addListener(String eventName) { - + // No-op: listeners are managed internally } @Override public void removeListeners(double count) { - + // No-op: listeners are managed internally } private void emitNativeStartupTime() { From b846df6385de3f657ef785afc1b8e3a47ec068fa Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Fri, 10 Oct 2025 17:09:44 +0200 Subject: [PATCH 6/7] Remove comments --- .../main/java/com/oblador/performance/PerformanceModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java index 58847fb..f0a51e6 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java @@ -138,12 +138,12 @@ public String getName() { @Override public void addListener(String eventName) { - // No-op: listeners are managed internally + } @Override public void removeListeners(double count) { - // No-op: listeners are managed internally + } private void emitNativeStartupTime() { From 762adbca900a55d10d8269367e23800c8e40b195 Mon Sep 17 00:00:00 2001 From: Mateusz Rajski Date: Mon, 13 Oct 2025 11:46:12 +0200 Subject: [PATCH 7/7] Remove override --- .../main/java/com/oblador/performance/PerformanceModule.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java index f0a51e6..0c457ce 100644 --- a/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java +++ b/packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java @@ -136,12 +136,10 @@ public String getName() { return PERFORMANCE_MODULE; } - @Override public void addListener(String eventName) { } - @Override public void removeListeners(double count) { }