diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 609d4db595824f..5dc25763469471 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -296,7 +296,6 @@ public final class com/facebook/react/ReactInstanceManagerBuilder { public final fun addPackages (Ljava/util/List;)Lcom/facebook/react/ReactInstanceManagerBuilder; public final fun build ()Lcom/facebook/react/ReactInstanceManager; public final fun setApplication (Landroid/app/Application;)Lcom/facebook/react/ReactInstanceManagerBuilder; - public final fun setBridgeIdleDebugListener (Lcom/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener;)Lcom/facebook/react/ReactInstanceManagerBuilder; public final fun setBundleAssetName (Ljava/lang/String;)Lcom/facebook/react/ReactInstanceManagerBuilder; public final fun setChoreographerProvider (Lcom/facebook/react/internal/ChoreographerProvider;)Lcom/facebook/react/ReactInstanceManagerBuilder; public final fun setCurrentActivity (Landroid/app/Activity;)Lcom/facebook/react/ReactInstanceManagerBuilder; @@ -583,7 +582,6 @@ public abstract interface class com/facebook/react/bridge/Callback { } public abstract interface class com/facebook/react/bridge/CatalystInstance : com/facebook/react/bridge/JSBundleLoaderDelegate, com/facebook/react/bridge/JSInstance, com/facebook/react/bridge/MemoryPressureListener { - public abstract fun addBridgeIdleDebugListener (Lcom/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener;)V public abstract fun callFunction (Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/NativeArray;)V public abstract fun destroy ()V public abstract fun extendNativeModules (Lcom/facebook/react/bridge/NativeModuleRegistry;)V @@ -605,7 +603,6 @@ public abstract interface class com/facebook/react/bridge/CatalystInstance : com public abstract fun invokeCallback (ILcom/facebook/react/bridge/NativeArrayInterface;)V public abstract fun isDestroyed ()Z public abstract fun registerSegment (ILjava/lang/String;)V - public abstract fun removeBridgeIdleDebugListener (Lcom/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener;)V public abstract fun runJSBundle ()V public abstract fun setFabricUIManager (Lcom/facebook/react/bridge/UIManager;)V public abstract fun setGlobalVariable (Ljava/lang/String;Ljava/lang/String;)V @@ -613,7 +610,6 @@ public abstract interface class com/facebook/react/bridge/CatalystInstance : com } public class com/facebook/react/bridge/CatalystInstanceImpl : com/facebook/react/bridge/CatalystInstance { - public fun addBridgeIdleDebugListener (Lcom/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener;)V public fun callFunction (Lcom/facebook/react/bridge/CatalystInstanceImpl$PendingJSCall;)V public fun callFunction (Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/NativeArray;)V public fun destroy ()V @@ -641,7 +637,6 @@ public class com/facebook/react/bridge/CatalystInstanceImpl : com/facebook/react public fun loadScriptFromFile (Ljava/lang/String;Ljava/lang/String;Z)V public fun loadSplitBundleFromFile (Ljava/lang/String;Ljava/lang/String;)V public fun registerSegment (ILjava/lang/String;)V - public fun removeBridgeIdleDebugListener (Lcom/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener;)V public fun runJSBundle ()V public fun setFabricUIManager (Lcom/facebook/react/bridge/UIManager;)V public fun setGlobalVariable (Ljava/lang/String;Ljava/lang/String;)V @@ -970,12 +965,6 @@ public final class com/facebook/react/bridge/NoSuchKeyException : java/lang/Runt public fun (Ljava/lang/String;)V } -public abstract interface class com/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener { - public abstract fun onBridgeDestroyed ()V - public abstract fun onTransitionToBridgeBusy ()V - public abstract fun onTransitionToBridgeIdle ()V -} - public abstract interface class com/facebook/react/bridge/PerformanceCounter { public abstract fun getPerformanceCounters ()Ljava/util/Map; public abstract fun profileNextBatch ()V @@ -4328,7 +4317,6 @@ public class com/facebook/react/uimanager/UIImplementation { public fun setJSResponder (IZ)V public fun setLayoutAnimationEnabledExperimental (Z)V public fun setLayoutUpdateListener (Lcom/facebook/react/uimanager/UIImplementation$LayoutUpdateListener;)V - public fun setViewHierarchyUpdateDebugListener (Lcom/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener;)V public fun setViewLocalData (ILjava/lang/Object;)V public fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/uimanager/ReactStylesDiffMap;)V public fun updateInsetsPadding (IIIII)V @@ -4412,7 +4400,6 @@ public class com/facebook/react/uimanager/UIManagerModule : com/facebook/react/b public fun setChildren (ILcom/facebook/react/bridge/ReadableArray;)V public fun setJSResponder (IZ)V public fun setLayoutAnimationEnabledExperimental (Z)V - public fun setViewHierarchyUpdateDebugListener (Lcom/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener;)V public fun setViewLocalData (ILjava/lang/Object;)V public fun startSurface (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/WritableMap;II)I public fun stopSurface (I)V @@ -4460,7 +4447,6 @@ public class com/facebook/react/uimanager/UIViewOperationQueue { public fun isEmpty ()Z public fun prependUIBlock (Lcom/facebook/react/uimanager/UIBlock;)V public fun profileNextBatch ()V - public fun setViewHierarchyUpdateDebugListener (Lcom/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener;)V } public abstract interface class com/facebook/react/uimanager/UIViewOperationQueue$UIOperation { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index a7943bda12746e..3578b02bd0f9bd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -57,7 +57,6 @@ import com.facebook.react.bridge.JavaScriptExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; import com.facebook.react.bridge.NativeModuleRegistry; -import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactCxxErrorHandler; @@ -183,7 +182,6 @@ public interface ReactInstanceEventListener private final boolean mUseDeveloperSupport; private final boolean mRequireActivity; private final boolean mKeepActivity; - private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener; private final Object mReactContextLock = new Object(); private @Nullable volatile ReactContext mCurrentReactContext; private final Context mApplicationContext; @@ -246,7 +244,6 @@ public static ReactInstanceManagerBuilder builder() { DevSupportManagerFactory devSupportManagerFactory, boolean requireActivity, boolean keepActivity, - @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener, LifecycleState initialLifecycleState, JSExceptionHandler jSExceptionHandler, @Nullable RedBoxHandler redBoxHandler, @@ -292,7 +289,6 @@ public static ReactInstanceManagerBuilder builder() { devLoadingViewManager, pausedInDebuggerOverlayManager); Systrace.endSection(TRACE_TAG_REACT); - mBridgeIdleDebugListener = bridgeIdleDebugListener; mLifecycleState = initialLifecycleState; mMemoryPressureRouter = new MemoryPressureRouter(applicationContext); mJSExceptionHandler = jSExceptionHandler; @@ -1517,9 +1513,6 @@ private ReactApplicationContext createReactContext( catalystInstance.setFabricUIManager(uiManager); } } - if (mBridgeIdleDebugListener != null) { - catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener); - } if (BuildConfig.ENABLE_PERFETTO || Systrace.isTracing(TRACE_TAG_REACT)) { catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true"); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.kt index 55ccfbe9bab5b2..d814bd96cfe664 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.kt @@ -19,7 +19,6 @@ import com.facebook.react.ReactInstanceManager.initializeSoLoaderIfNecessary import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.bridge.JSExceptionHandler import com.facebook.react.bridge.JavaScriptExecutorFactory -import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener import com.facebook.react.bridge.UIManagerProvider import com.facebook.react.common.LifecycleState import com.facebook.react.common.SurfaceDelegateFactory @@ -49,7 +48,6 @@ public class ReactInstanceManagerBuilder { private var jsBundleAssetUrl: String? = null private var jsBundleLoader: JSBundleLoader? = null private var jsMainModulePath: String? = null - private var bridgeIdleDebugListener: NotThreadSafeBridgeIdleDebugListener? = null private var application: Application? = null private var useDeveloperSupport = false private var devSupportManagerFactory: DevSupportManagerFactory? = null @@ -145,13 +143,6 @@ public class ReactInstanceManagerBuilder { return this } - public fun setBridgeIdleDebugListener( - bridgeIdleDebugListener: NotThreadSafeBridgeIdleDebugListener - ): ReactInstanceManagerBuilder { - this.bridgeIdleDebugListener = bridgeIdleDebugListener - return this - } - /** Required. This must be your `Application` instance. */ public fun setApplication(application: Application): ReactInstanceManagerBuilder { this.application = application @@ -359,7 +350,6 @@ public class ReactInstanceManagerBuilder { devSupportManagerFactory ?: DefaultDevSupportManagerFactory(), requireActivity, keepActivity, - bridgeIdleDebugListener, checkNotNull(initialLifecycleState) { "Initial lifecycle state was not set" }, jsExceptionHandler, redBoxHandler, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.kt index 81ee574dd1d604..df0a40ec2409bd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.kt @@ -75,24 +75,6 @@ public interface CatalystInstance : MemoryPressureListener, JSInstance, JSBundle */ public fun extendNativeModules(modules: NativeModuleRegistry) - /** - * Adds a idle listener for this Catalyst instance. The listener will receive notifications - * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is - * defined as there being some non-zero number of calls to JS that haven't resolved via a - * onBatchCompleted call. The listener should be purely passive and not affect application logic. - */ - public fun addBridgeIdleDebugListener( - @Suppress("DEPRECATION") listener: NotThreadSafeBridgeIdleDebugListener - ) - - /** - * Removes a NotThreadSafeBridgeIdleDebugListener previously added with - * [addBridgeIdleDebugListener] - */ - public fun removeBridgeIdleDebugListener( - @Suppress("DEPRECATION") listener: NotThreadSafeBridgeIdleDebugListener - ) - /** This method registers the file path of an additional JS segment by its ID. */ public fun registerSegment(segmentId: Int, path: String) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index f3e799d1417854..194f33acc35c4b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -39,7 +39,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; /** @@ -88,7 +87,6 @@ public String toString() { // Access from any thread private final ReactQueueConfigurationImpl mReactQueueConfiguration; - private final CopyOnWriteArrayList mBridgeIdleListeners; private final AtomicInteger mPendingJSCalls = new AtomicInteger(0); private final String mJsPendingCallsTitleForTrace = "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement(); @@ -138,7 +136,6 @@ private CatalystInstanceImpl( mReactQueueConfiguration = ReactQueueConfigurationImpl.create( reactQueueConfigurationSpec, new NativeExceptionHandler()); - mBridgeIdleListeners = new CopyOnWriteArrayList<>(); mNativeModuleRegistry = nativeModuleRegistry; mJSModuleRegistry = new JavaScriptModuleRegistry(); mJSBundleLoader = jsBundleLoader; @@ -372,14 +369,6 @@ public void destroy() { mFabricUIManager.invalidate(); } boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0); - if (!mBridgeIdleListeners.isEmpty()) { - for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) { - if (!wasIdle) { - listener.onTransitionToBridgeIdle(); - } - listener.onBridgeDestroyed(); - } - } getReactQueueConfiguration() .getJSQueueThread() @@ -521,30 +510,6 @@ public void handleMemoryPressure(int level) { jniHandleMemoryPressure(level); } - /** - * Adds a idle listener for this Catalyst instance. The listener will receive notifications - * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is - * defined as there being some non-zero number of calls to JS that haven't resolved via a - * onBatchComplete call. The listener should be purely passive and not affect application logic. - * - * @noinspection deprecation - */ - @Override - public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) { - mBridgeIdleListeners.add(listener); - } - - /** - * Removes a NotThreadSafeBridgeIdleDebugListener previously added with {@link - * #addBridgeIdleDebugListener} - * - * @noinspection deprecation - */ - @Override - public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) { - mBridgeIdleListeners.remove(listener); - } - @Override public native void setGlobalVariable(String propName, String jsonValue); @@ -561,16 +526,7 @@ public JavaScriptContextHolder getJavaScriptContextHolder() { private void incrementPendingJSCalls() { int oldPendingCalls = mPendingJSCalls.getAndIncrement(); - boolean wasIdle = oldPendingCalls == 0; Systrace.traceCounter(TRACE_TAG_REACT, mJsPendingCallsTitleForTrace, oldPendingCalls + 1); - if (wasIdle && !mBridgeIdleListeners.isEmpty()) { - mNativeModulesQueueThread.runOnQueue( - () -> { - for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) { - listener.onTransitionToBridgeBusy(); - } - }); - } } @Override @@ -592,17 +548,7 @@ private void decrementPendingJSCalls() { int newPendingCalls = mPendingJSCalls.decrementAndGet(); // TODO(9604406): handle case of web workers injecting messages to main thread // Assertions.assertCondition(newPendingCalls >= 0); - boolean isNowIdle = newPendingCalls == 0; Systrace.traceCounter(TRACE_TAG_REACT, mJsPendingCallsTitleForTrace, newPendingCalls); - - if (isNowIdle && !mBridgeIdleListeners.isEmpty()) { - mNativeModulesQueueThread.runOnQueue( - () -> { - for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) { - listener.onTransitionToBridgeIdle(); - } - }); - } } private void onNativeException(Exception e) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener.kt deleted file mode 100644 index ab9fd1d69fc2aa..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.bridge - -import com.facebook.react.common.annotations.internal.LegacyArchitecture -import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel - -/** - * Interface for receiving notification for bridge idle/busy events. Should not affect application - * logic and should only be used for debug/monitoring/testing purposes. Call - * [ ][CatalystInstance.addBridgeIdleDebugListener] to start monitoring. - * - * NB: onTransitionToBridgeIdle and onTransitionToBridgeBusy may be called from different threads, - * and those threads may not be the same thread on which the listener was originally registered. - */ -@Deprecated("NotThreadSafeBridgeIdleDebugListener will be deleted in the new architecture.") -@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR) -public interface NotThreadSafeBridgeIdleDebugListener { - /** - * Called once all pending JS calls have resolved via an onBatchComplete call in the bridge and - * the requested native module calls have also run. The bridge will not become busy again until a - * timer, touch event, etc. causes a Java->JS call to be enqueued again. - */ - public fun onTransitionToBridgeIdle() - - /** Called when the bridge was in an idle state and executes a JS call or callback. */ - public fun onTransitionToBridgeBusy() - - /** Called when the bridge is destroyed */ - public fun onBridgeDestroyed() -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.kt deleted file mode 100644 index 10ab8c2ca54474..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -@file:Suppress( - "DEPRECATION" -) // Suppressing deprecation of NotThreadSafeViewHierarchyUpdateDebugListener - -package com.facebook.react.modules.debug - -import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener -import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener - -/** - * Debug object that listens to bridge busy/idle events and UiManagerModule dispatches and uses it - * to calculate whether JS was able to update the UI during a given frame. After being installed on - * a [ReactBridge] and a [com.facebook.react.uimanager.UIManagerModule], - * [getDidJSHitFrameAndCleanup] should be called once per frame via a - * [android.view.Choreographer.FrameCallback]. - */ -internal class DidJSUpdateUiDuringFrameDetector : - NotThreadSafeBridgeIdleDebugListener, NotThreadSafeViewHierarchyUpdateDebugListener { - private val transitionToIdleEvents = ArrayList(20) - private val transitionToBusyEvents = ArrayList(20) - private val viewHierarchyUpdateEnqueuedEvents = ArrayList(20) - private val viewHierarchyUpdateFinishedEvents = ArrayList(20) - @Volatile private var wasIdleAtEndOfLastFrame = true - - @Synchronized - override fun onTransitionToBridgeIdle() { - transitionToIdleEvents.add(System.nanoTime()) - } - - @Synchronized - override fun onTransitionToBridgeBusy() { - transitionToBusyEvents.add(System.nanoTime()) - } - - @Synchronized - override fun onBridgeDestroyed() { - // do nothing - } - - @Synchronized - override fun onViewHierarchyUpdateEnqueued() { - viewHierarchyUpdateEnqueuedEvents.add(System.nanoTime()) - } - - @Synchronized - override fun onViewHierarchyUpdateFinished() { - viewHierarchyUpdateFinishedEvents.add(System.nanoTime()) - } - - /** - * Designed to be called from a [android.view.Choreographer.FrameCallback.doFrame] call. - * - * There are two 'success' cases that will cause [getDidJSHitFrameAndCleanup] to return true for a - * given frame: - * 1. UIManagerModule finished dispatching a batched UI update on the UI thread during the frame. - * This means that during the next hierarchy traversal, new UI will be drawn if needed (good). - * 1. The bridge ended the frame idle (meaning there were no JS nor native module calls still in - * flight) AND there was no UiManagerModule update enqueued that didn't also finish. NB: if - * there was one enqueued that actually finished, we'd have case 1), so effectively we just - * look for whether one was enqueued. - * - * NB: This call can only be called once for a given frame time range because it cleans up events - * it recorded for that frame. - * - * NB2: This makes the assumption that [onViewHierarchyUpdateEnqueued] is called from the - * [com.facebook.react.uimanager.UIManagerModule.onBatchComplete], e.g. while the bridge is still - * considered busy, which means there is no race condition where the bridge has gone idle but a - * hierarchy update is waiting to be enqueued. - * - * @param frameStartTimeNanos the time in nanos that the last frame started - * @param frameEndTimeNanos the time in nanos that the last frame ended - */ - @Synchronized - fun getDidJSHitFrameAndCleanup(frameStartTimeNanos: Long, frameEndTimeNanos: Long): Boolean { - // Case 1: We dispatched a UI update - val finishedUiUpdate = - hasEventBetweenTimestamps( - viewHierarchyUpdateFinishedEvents, - frameStartTimeNanos, - frameEndTimeNanos, - ) - val didEndFrameIdle = didEndFrameIdle(frameStartTimeNanos, frameEndTimeNanos) - val hitFrame = - if (finishedUiUpdate) { - true - } else { - // Case 2: Ended idle but no UI was enqueued during that frame - (didEndFrameIdle && - !hasEventBetweenTimestamps( - viewHierarchyUpdateEnqueuedEvents, - frameStartTimeNanos, - frameEndTimeNanos, - )) - } - cleanUp(transitionToIdleEvents, frameEndTimeNanos) - cleanUp(transitionToBusyEvents, frameEndTimeNanos) - cleanUp(viewHierarchyUpdateEnqueuedEvents, frameEndTimeNanos) - cleanUp(viewHierarchyUpdateFinishedEvents, frameEndTimeNanos) - wasIdleAtEndOfLastFrame = didEndFrameIdle - return hitFrame - } - - private fun didEndFrameIdle(startTime: Long, endTime: Long): Boolean { - val lastIdleTransition = - getLastEventBetweenTimestamps(transitionToIdleEvents, startTime, endTime) - val lastBusyTransition = - getLastEventBetweenTimestamps(transitionToBusyEvents, startTime, endTime) - return if (lastIdleTransition == -1L && lastBusyTransition == -1L) { - wasIdleAtEndOfLastFrame - } else lastIdleTransition > lastBusyTransition - } -} - -private fun hasEventBetweenTimestamps( - eventArray: ArrayList, - startTime: Long, - endTime: Long, -): Boolean = eventArray.any { time -> time in startTime until endTime } - -private fun getLastEventBetweenTimestamps( - eventArray: ArrayList, - startTime: Long, - endTime: Long, -): Long { - var lastEvent: Long = -1 - for (time in eventArray) { - if (time in startTime until endTime) { - lastEvent = time - } else if (time >= endTime) { - break - } - } - return lastEvent -} - -private fun cleanUp(eventArray: ArrayList, endTime: Long) { - val size = eventArray.size - var indicesToRemove = 0 - for (i in 0 until size) { - if (eventArray[i] < endTime) { - indicesToRemove++ - } - } - if (indicesToRemove > 0) { - for (i in 0 until size - indicesToRemove) { - eventArray[i] = eventArray[i + indicesToRemove] - } - eventArray.dropLast(indicesToRemove) - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt index 8fd2bd42291cbd..b25be20d9f9b1f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt @@ -26,8 +26,6 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : Choreographer.FrameCallback { private var choreographer: Choreographer? = null - private val didJSUpdateUiDuringFrameDetector: DidJSUpdateUiDuringFrameDetector = - DidJSUpdateUiDuringFrameDetector() private var firstFrameTime: Long = -1 private var lastFrameTime: Long = -1 private var numFrameCallbacks = 0 @@ -40,11 +38,7 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : if (firstFrameTime == -1L) { firstFrameTime = l } - val lastFrameStartTime = lastFrameTime lastFrameTime = l - if (didJSUpdateUiDuringFrameDetector.getDidJSHitFrameAndCleanup(lastFrameStartTime, l)) { - numFrameCallbacksWithBatchDispatches++ - } numFrameCallbacks++ val expectedNumFrames = expectedNumFrames val framesDropped = expectedNumFrames - expectedNumFramesPrev - 1 @@ -61,17 +55,9 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : // removeBridgeIdleDebugListener for Bridgeless @Suppress("DEPRECATION") if (!ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) { - val uiManagerModule = - reactContext.getNativeModule(com.facebook.react.uimanager.UIManagerModule::class.java) - if (!reactContext.isBridgeless) { - reactContext.catalystInstance.addBridgeIdleDebugListener(didJSUpdateUiDuringFrameDetector) - isRunningOnFabric = false - } else { - // T172641976 Consider either implementing a mechanism similar to addBridgeIdleDebugListener - // for Fabric or point users to use RNDT. - isRunningOnFabric = true - } - uiManagerModule?.setViewHierarchyUpdateDebugListener(didJSUpdateUiDuringFrameDetector) + // T172641976 Consider either implementing a mechanism similar to addBridgeIdleDebugListener + // for Fabric or point users to use RNDT. + isRunningOnFabric = true } this.targetFps = targetFps UiThreadUtil.runOnUiThread { @@ -82,16 +68,6 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : fun stop() { @Suppress("DEPRECATION") - if (!ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) { - val uiManagerModule = - reactContext.getNativeModule(com.facebook.react.uimanager.UIManagerModule::class.java) - if (!reactContext.isBridgeless) { - reactContext.catalystInstance.removeBridgeIdleDebugListener( - didJSUpdateUiDuringFrameDetector - ) - } - uiManagerModule?.setViewHierarchyUpdateDebugListener(null) - } UiThreadUtil.runOnUiThread { choreographer = Choreographer.getInstance() choreographer?.removeFrameCallback(this) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt index d70ec496050aaa..1a65c44a5e61fe 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt @@ -19,7 +19,6 @@ import com.facebook.react.bridge.NativeArray import com.facebook.react.bridge.NativeArrayInterface import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.NativeModuleRegistry -import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener import com.facebook.react.bridge.RuntimeExecutor import com.facebook.react.bridge.RuntimeScheduler import com.facebook.react.bridge.UIManager @@ -140,14 +139,6 @@ internal class BridgelessCatalystInstance(private val reactHost: ReactHostImpl) override val sourceURL: String get() = throw UnsupportedOperationException("Unimplemented method 'getSourceURL'") - override fun addBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) { - throw UnsupportedOperationException("Unimplemented method 'addBridgeIdleDebugListener'") - } - - override fun removeBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) { - throw UnsupportedOperationException("Unimplemented method 'removeBridgeIdleDebugListener'") - } - override fun registerSegment(segmentId: Int, path: String) { throw UnsupportedOperationException("Unimplemented method 'registerSegment'") } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index 2cf717f3703d25..4576b857303a6b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -26,7 +26,6 @@ import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger; import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.modules.i18nmanager.I18nUtil; -import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; @@ -782,13 +781,6 @@ public void onCatalystInstanceDestroyed() { mViewManagers.invalidate(); } - // NOTE: When converted to Kotlin this method should be `internal` due to - // visibility restriction for `NotThreadSafeViewHierarchyUpdateDebugListener` - public void setViewHierarchyUpdateDebugListener( - @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) { - mOperationsQueue.setViewHierarchyUpdateDebugListener(listener); - } - protected final void removeShadowNode(ReactShadowNode nodeToRemove) { removeShadowNodeRecursive(nodeToRemove); nodeToRemove.dispose(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 920096ea7418b6..416fc3a261e017 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -45,7 +45,6 @@ import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.common.ViewUtil; -import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.EventDispatcherImpl; import com.facebook.react.uimanager.events.RCTEventEmitter; @@ -699,13 +698,6 @@ public void onBatchComplete() { } } - // NOTE: When converted to Kotlin this method should be `internal` due to - // visibility restriction for `NotThreadSafeViewHierarchyUpdateDebugListener` - public void setViewHierarchyUpdateDebugListener( - @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) { - mUIImplementation.setViewHierarchyUpdateDebugListener(listener); - } - @Override public EventDispatcher getEventDispatcher() { return mEventDispatcher; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java index 6745ca88c5fe0e..8d46ee3eb49e43 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java @@ -29,7 +29,6 @@ import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel; import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger; import com.facebook.react.modules.core.ReactChoreographer; -import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; import com.facebook.yoga.YogaDirection; @@ -584,7 +583,6 @@ public void execute() { @GuardedBy("mNonBatchedOperationsLock") private ArrayDeque mNonBatchedOperations = new ArrayDeque<>(); - private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener; private boolean mIsDispatchUIFrameCallbackEnqueued = false; private boolean mIsInIllegalUIState = false; private boolean mIsProfilingNextBatch = false; @@ -619,13 +617,6 @@ public UIViewOperationQueue( return mNativeViewHierarchyManager; } - // NOTE: When converted to Kotlin this method should be `internal` due to - // visibility restriction for `NotThreadSafeViewHierarchyUpdateDebugListener` - public void setViewHierarchyUpdateDebugListener( - @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) { - mViewHierarchyUpdateDebugListener = listener; - } - public void profileNextBatch() { mIsProfilingNextBatch = true; mProfiledBatchCommitStartTime = 0; @@ -833,10 +824,6 @@ public void dispatchViewUpdates( } } - if (mViewHierarchyUpdateDebugListener != null) { - mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateEnqueued(); - } - Runnable runOperations = new Runnable() { @Override @@ -926,9 +913,6 @@ public void run() { // Clear layout animation, as animation only apply to current UI operations batch. mNativeViewHierarchyManager.clearLayoutAnimation(); - if (mViewHierarchyUpdateDebugListener != null) { - mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateFinished(); - } } catch (Exception e) { mIsInIllegalUIState = true; throw e; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.kt deleted file mode 100644 index abeda63335f1ef..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.uimanager.debug - -import com.facebook.react.common.annotations.internal.LegacyArchitecture -import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel - -/** - * A listener that is notified about view hierarchy update events. This listener should only be used - * for debug purposes and should not affect application state. - * - * NB: while [onViewHierarchyUpdateFinished] will always be called from the UI thread, there are no - * guarantees what thread onViewHierarchyUpdateEnqueued is called on. - */ -@Deprecated( - "NotThreadSafeViewHierarchyUpdateDebugListener will be deleted in the new architecture." -) -@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR) -internal interface NotThreadSafeViewHierarchyUpdateDebugListener { - /** Called when `UIManagerModule` enqueues a UI batch to be dispatched to the main thread. */ - fun onViewHierarchyUpdateEnqueued() - - /** Called from the main thread after a UI batch has been applied to all root views. */ - fun onViewHierarchyUpdateFinished() -}