diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index f5b43205099..006398ac7d9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -66,6 +66,8 @@ public class ReactFeatureFlags { public static boolean enableLockFreeEventDispatcher = false; + public static boolean enableAggressiveEventEmitterCleanup = false; + // // ScrollView C++ UpdateState vs onScroll race fixes // diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java index 7938b793c5d..69d0e1c8a8a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java @@ -48,13 +48,11 @@ public class EventEmitterWrapper { * @param params {@link WritableMap} payload of the event */ public void invoke(@NonNull String eventName, @Nullable WritableMap params) { - synchronized (mHybridData) { - if (!isValid()) { - return; - } - NativeMap payload = params == null ? new WritableNativeMap() : (NativeMap) params; - invokeEvent(eventName, payload); + if (!isValid()) { + return; } + NativeMap payload = params == null ? new WritableNativeMap() : (NativeMap) params; + invokeEvent(eventName, payload); } /** @@ -66,20 +64,16 @@ public class EventEmitterWrapper { */ public void invokeUnique( @NonNull String eventName, @Nullable WritableMap params, int customCoalesceKey) { - synchronized (mHybridData) { - if (!isValid()) { - return; - } - NativeMap payload = params == null ? new WritableNativeMap() : (NativeMap) params; - invokeUniqueEvent(eventName, payload, customCoalesceKey); + if (!isValid()) { + return; } + NativeMap payload = params == null ? new WritableNativeMap() : (NativeMap) params; + invokeUniqueEvent(eventName, payload, customCoalesceKey); } public void destroy() { - synchronized (mHybridData) { - if (mHybridData != null) { - mHybridData.resetNative(); - } + if (mHybridData != null) { + mHybridData.resetNative(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index cb2179bc6fb..9aa47320d35 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -1151,11 +1151,14 @@ void Binding::preallocateShadowView( } // Do not hold a reference to javaEventEmitter from the C++ side. - auto javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs(); + local_ref javaEventEmitter = nullptr; if (enableEarlyEventEmitterUpdate_) { SharedEventEmitter eventEmitter = shadowView.eventEmitter; - EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter); - cEventEmitter->eventEmitter = eventEmitter; + if (eventEmitter != nullptr) { + javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs(); + EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter); + cEventEmitter->eventEmitter = eventEmitter; + } } local_ref props = castReadableMap( @@ -1169,7 +1172,7 @@ void Binding::preallocateShadowView( component.get(), props.get(), (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr), - javaEventEmitter.get(), + (javaEventEmitter != nullptr ? javaEventEmitter.get() : nullptr), isLayoutableShadowNode); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.cpp index afb73f9927a..b4e98990575 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.cpp @@ -21,8 +21,13 @@ EventEmitterWrapper::initHybrid(jni::alias_ref) { void EventEmitterWrapper::invokeEvent( std::string eventName, NativeMap *payload) { - eventEmitter->dispatchEvent( - eventName, payload->consume(), EventPriority::AsynchronousBatched); + // It is marginal, but possible for this to be constructed without a valid + // EventEmitter. In those cases, make sure we noop/blackhole events instead of + // crashing. + if (eventEmitter != nullptr) { + eventEmitter->dispatchEvent( + eventName, payload->consume(), EventPriority::AsynchronousBatched); + } } void EventEmitterWrapper::invokeUniqueEvent( @@ -30,7 +35,12 @@ void EventEmitterWrapper::invokeUniqueEvent( NativeMap *payload, int customCoalesceKey) { // TODO: customCoalesceKey currently unused - eventEmitter->dispatchUniqueEvent(eventName, payload->consume()); + // It is marginal, but possible for this to be constructed without a valid + // EventEmitter. In those cases, make sure we noop/blackhole events instead of + // crashing. + if (eventEmitter != nullptr) { + eventEmitter->dispatchUniqueEvent(eventName, payload->consume()); + } } void EventEmitterWrapper::registerNatives() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index ba39ab4a613..f394b073c1a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -27,6 +27,7 @@ import com.facebook.react.bridge.RetryableMountingLayerException; import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.mounting.MountingManager.MountItemExecutor; import com.facebook.react.fabric.mounting.mountitems.MountItem; @@ -250,9 +251,11 @@ public class SurfaceMountingManager { viewState.mStateWrapper.destroyState(); viewState.mStateWrapper = null; } - if (viewState.mEventEmitter != null) { - viewState.mEventEmitter.destroy(); - viewState.mEventEmitter = null; + if (ReactFeatureFlags.enableAggressiveEventEmitterCleanup) { + if (viewState.mEventEmitter != null) { + viewState.mEventEmitter.destroy(); + viewState.mEventEmitter = null; + } } }