Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,15 @@ public abstract interface class com/facebook/react/devsupport/interfaces/StackFr
public abstract fun toJSON ()Lorg/json/JSONObject;
}

public final class com/facebook/react/devsupport/interfaces/TracingState : java/lang/Enum {
public static final field DISABLED Lcom/facebook/react/devsupport/interfaces/TracingState;
public static final field ENABLEDINBACKGROUNDMODE Lcom/facebook/react/devsupport/interfaces/TracingState;
public static final field ENABLEDINCDPMODE Lcom/facebook/react/devsupport/interfaces/TracingState;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public static fun valueOf (Ljava/lang/String;)Lcom/facebook/react/devsupport/interfaces/TracingState;
public static fun values ()[Lcom/facebook/react/devsupport/interfaces/TracingState;
}

public final class com/facebook/react/fabric/ComponentFactory {
public fun <init> ()V
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.facebook.react.devsupport.interfaces.DevLoadingViewManager
import com.facebook.react.devsupport.interfaces.DevSupportManager
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager
import com.facebook.react.devsupport.interfaces.RedBoxHandler
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.packagerconnection.RequestHandler

/**
Expand Down Expand Up @@ -80,4 +81,8 @@ internal class BridgelessDevSupportManager(
hideRedboxDialog()
reactInstanceDevHelper.reload("BridgelessDevSupportManager.handleReloadJS()")
}

fun tracingState(): TracingState {
return TracingState.DISABLED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import com.facebook.react.devsupport.InspectorFlags.getFuseboxEnabled
import com.facebook.react.devsupport.StackTraceHelper.convertJavaStackTrace
import com.facebook.react.devsupport.StackTraceHelper.convertJsStackTrace
import com.facebook.react.devsupport.interfaces.BundleLoadCallback
import com.facebook.react.devsupport.interfaces.DebuggerFrontendPanelName
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager
import com.facebook.react.devsupport.interfaces.DevOptionHandler
Expand All @@ -64,6 +65,8 @@ import com.facebook.react.devsupport.interfaces.PackagerStatusCallback
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager
import com.facebook.react.devsupport.interfaces.RedBoxHandler
import com.facebook.react.devsupport.interfaces.StackFrame
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.devsupport.interfaces.TracingStateProvider
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
Expand Down Expand Up @@ -180,6 +183,7 @@ public abstract class DevSupportManagerBase(
}

private var perfMonitorOverlayManager: PerfMonitorOverlayViewManager? = null
private var tracingStateProvider: TracingStateProvider? = null

init {
// We store JS bundle loaded from dev server in a single destination in app's data dir.
Expand Down Expand Up @@ -358,6 +362,43 @@ public abstract class DevSupportManagerBase(
options[debuggerItemString] = DevOptionHandler { this.openDebugger() }
}

if (ReactNativeFeatureFlags.perfMonitorV2Enabled()) {
val isConnected = isPackagerConnected
val tracingState = tracingStateProvider?.getTracingState() ?: TracingState.DISABLED

val analyzePerformanceItemString =
when (tracingState) {
TracingState.ENABLEDINBACKGROUNDMODE ->
applicationContext.getString(R.string.catalyst_performance_background)
TracingState.ENABLEDINCDPMODE ->
applicationContext.getString(R.string.catalyst_performance_cdp)
TracingState.DISABLED ->
applicationContext.getString(R.string.catalyst_performance_disabled)
}

if (!isConnected || tracingState == TracingState.ENABLEDINCDPMODE) {
disabledItemKeys.add(analyzePerformanceItemString)
}

options[analyzePerformanceItemString] =
when (tracingState) {
TracingState.ENABLEDINBACKGROUNDMODE ->
DevOptionHandler {
UiThreadUtil.runOnUiThread {
if (reactInstanceDevHelper is PerfMonitorDevHelper)
reactInstanceDevHelper.inspectorTarget?.pauseAndAnalyzeBackgroundTrace()
}
openDebugger(DebuggerFrontendPanelName.PERFORMANCE.toString())
}
TracingState.DISABLED ->
DevOptionHandler {
if (reactInstanceDevHelper is PerfMonitorDevHelper)
reactInstanceDevHelper.inspectorTarget?.resumeBackgroundTrace()
}
TracingState.ENABLEDINCDPMODE -> DevOptionHandler {}
}
}

options[applicationContext.getString(R.string.catalyst_change_bundle_location)] =
DevOptionHandler {
val context = reactInstanceDevHelper.currentActivity
Expand Down Expand Up @@ -942,6 +983,14 @@ public abstract class DevSupportManagerBase(
devSettings.packagerConnectionSettings.setAdditionalOptionForPackager(name, value)
}

/**
* Sets the background tracing state provider for bridgeless architecture. This is called
* internally by the ReactHost implementation.
*/
internal fun setTracingStateProvider(provider: TracingStateProvider?) {
tracingStateProvider = provider
}

public companion object {
private const val JAVA_ERROR_COOKIE = -1
private const val JSEXCEPTION_ERROR_COOKIE = -1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import androidx.core.view.WindowInsetsCompat
import com.facebook.react.R
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.devsupport.interfaces.PerfMonitorOverlayManager
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTargetBinding
import com.facebook.react.devsupport.perfmonitor.PerfMonitorUpdateListener
import com.facebook.react.uimanager.DisplayMetricsHolder
Expand Down Expand Up @@ -68,6 +69,11 @@ internal class PerfMonitorOverlayViewManager(
}
}

override fun onRecordingStateChanged(state: TracingState) {
// recordingState = state
// view?.updateRecordingState(state)
}

override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
UiThreadUtil.runOnUiThread {
ensureInitialized()
Expand Down Expand Up @@ -148,6 +154,8 @@ internal class PerfMonitorOverlayViewManager(
this.interactionDialog = dialog
}

fun updateRecordingState(state: TracingState) {}

private fun createButton(context: Context) {
val buttonInner = createInnerLayout(context)
buttonInner.addView(
Expand Down Expand Up @@ -177,7 +185,7 @@ internal class PerfMonitorOverlayViewManager(
dpToPx(8f).toInt(),
)
addView(buttonInner)
setOnClickListener { inspectorTarget?.pauseAndAnalyzeTrace() }
setOnClickListener { inspectorTarget?.pauseAndAnalyzeBackgroundTrace() }
}
val dialog =
createAnchoredDialog(context, dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.devsupport.interfaces

import com.facebook.proguard.annotations.DoNotStripAny

// Keep in sync with `TracingState.h`
// JNI wrapper for `jsinspector_modern::Tracing::TracingState`.
@DoNotStripAny
public enum class TracingState {
DISABLED, // There is no active trace
ENABLEDINBACKGROUNDMODE, // Trace is currently running in background mode
ENABLEDINCDPMODE, // Trace is currently running in CDP mode
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.devsupport.interfaces

internal interface TracingStateProvider {
fun getTracingState(): TracingState
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ package com.facebook.react.devsupport.perfmonitor
* exposing actions for the V2 Perf Monitor.
*/
internal interface PerfMonitorInspectorTargetBinding {
public fun pauseAndAnalyzeTrace()
/** Attempt to pause the current background performance trace, and open in DevTools. */
public fun pauseAndAnalyzeBackgroundTrace()

/** Attempt to start a new background performance trace. */
public fun resumeBackgroundTrace()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
* 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.devsupport.perfmonitor

import com.facebook.react.devsupport.interfaces.TracingState

/** [Experimental] An interface for subscribing to updates for the V2 Perf Monitor. */
internal interface PerfMonitorUpdateListener {
data class LongTaskEventData(
Expand All @@ -17,4 +18,7 @@ internal interface PerfMonitorUpdateListener {

/** Called when a new active performance event should be displayed. */
fun onNewFocusedEvent(data: LongTaskEventData)

/** Called when the recording state of the background performance trace has changed. */
fun onRecordingStateChanged(state: TracingState)
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,30 @@ public class ReactHostImpl(
private val useDevSupport: Boolean,
devSupportManagerFactory: DevSupportManagerFactory? = null,
) : ReactHost {
private val reactHostImplDevHelper = ReactHostImplDevHelper(this)

public override val devSupportManager: DevSupportManager =
(devSupportManagerFactory ?: DefaultDevSupportManagerFactory()).create(
applicationContext = context.applicationContext,
reactInstanceManagerHelper = ReactHostImplDevHelper(this),
packagerPathForJSBundleName = reactHostDelegate.jsMainModulePath,
enableOnCreate = true,
redBoxHandler = null,
devBundleDownloadListener = null,
minNumShakes = 2,
customPackagerCommandHandlers = null,
surfaceDelegateFactory = null,
devLoadingViewManager = null,
pausedInDebuggerOverlayManager = null,
useDevSupport = useDevSupport,
)
(devSupportManagerFactory ?: DefaultDevSupportManagerFactory())
.create(
applicationContext = context.applicationContext,
reactInstanceManagerHelper = reactHostImplDevHelper,
packagerPathForJSBundleName = reactHostDelegate.jsMainModulePath,
enableOnCreate = true,
redBoxHandler = null,
devBundleDownloadListener = null,
minNumShakes = 2,
customPackagerCommandHandlers = null,
surfaceDelegateFactory = null,
devLoadingViewManager = null,
pausedInDebuggerOverlayManager = null,
useDevSupport = useDevSupport,
)
.also { devSupportManager ->
// Wire up the tracing state provider
if (devSupportManager is DevSupportManagerBase) {
devSupportManager.setTracingStateProvider(reactHostImplDevHelper)
}
}
public override val memoryPressureRouter: MemoryPressureRouter = MemoryPressureRouter(context)

private val attachedSurfaces: MutableSet<ReactSurfaceImpl> = HashSet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import com.facebook.react.bridge.ReactContext
import com.facebook.react.common.annotations.FrameworkAPI
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.devsupport.ReactInstanceDevHelper
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.devsupport.interfaces.TracingStateProvider
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTarget
import com.facebook.react.interfaces.TaskInterface
Expand All @@ -30,7 +32,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
@UnstableReactNativeAPI
@OptIn(FrameworkAPI::class)
internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :
ReactInstanceDevHelper, PerfMonitorDevHelper {
ReactInstanceDevHelper, PerfMonitorDevHelper, TracingStateProvider {

override val currentActivity: Activity?
get() = delegate.lastUsedActivity
Expand Down Expand Up @@ -77,4 +79,8 @@ internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :

override fun loadBundle(bundleLoader: JSBundleLoader): TaskInterface<Boolean> =
delegate.loadBundle(bundleLoader)

override fun getTracingState(): TracingState {
return delegate.reactHostInspectorTarget?.tracingState() ?: TracingState.DISABLED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.facebook.proguard.annotations.DoNotStripAny
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.common.annotations.FrameworkAPI
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.devsupport.interfaces.TracingState
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTarget
import com.facebook.react.devsupport.perfmonitor.PerfMonitorUpdateListener
import com.facebook.soloader.SoLoader
Expand Down Expand Up @@ -40,12 +41,28 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) :

external fun stopAndDiscardBackgroundTrace()

external fun tracingStateAsInt(): Int

fun tracingState(): TracingState {
return TracingState.entries[tracingStateAsInt()]
}

override fun addPerfMonitorListener(listener: PerfMonitorUpdateListener) {
perfMonitorListeners.add(listener)
}

override fun pauseAndAnalyzeTrace() {
// TODO(T233874551)
override fun pauseAndAnalyzeBackgroundTrace() {
stopAndStashBackgroundTrace()
perfMonitorListeners.forEach { listener ->
listener.onRecordingStateChanged(TracingState.DISABLED)
}
}

override fun resumeBackgroundTrace() {
startBackgroundTrace()
perfMonitorListeners.forEach { listener ->
listener.onRecordingStateChanged(TracingState.ENABLEDINBACKGROUNDMODE)
}
}

fun handleNativePerfMonitorMetricUpdate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,14 @@ void JReactHostInspectorTarget::registerNatives() {
makeNativeMethod(
"stopAndDiscardBackgroundTrace",
JReactHostInspectorTarget::stopAndDiscardBackgroundTrace),
makeNativeMethod(
"tracingStateAsInt", JReactHostInspectorTarget::tracingState),
});
}

jint JReactHostInspectorTarget::tracingState() {
auto state = inspectorTarget_->tracingState();
return static_cast<jint>(state);
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ struct JTaskInterface : public jni::JavaClass<JTaskInterface> {
"Lcom/facebook/react/interfaces/TaskInterface;";
};

struct JTracingState : public jni::JavaClass<JTracingState> {
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/devsupport/TracingState;";
};

struct JReactHostImpl : public jni::JavaClass<JReactHostImpl> {
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/runtime/ReactHostImpl;";
Expand Down Expand Up @@ -88,6 +93,14 @@ class JReactHostInspectorTarget
* which will be emitted the next time CDP session is created.
*/
void stopAndStashBackgroundTrace();
/**
* Get the state of the background trace: running, stopped, or disabled
* Background tracing will be disabled if there is no metro connection or if
* there is a CDP initiate trace in progress.
*
* \return the background trace state
*/
jint tracingState();
/**
* Stops previously started trace recording and discards the captured trace.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<string name="catalyst_change_bundle_location_cancel" project="catalyst" translatable="false">Cancel</string>
<string name="catalyst_open_debugger_error" project="catalyst" translatable="false">Failed to open DevTools. Please check that the dev server is running and reload the app.</string>
<string name="catalyst_debug_open" project="catalyst" translatable="false">Open DevTools</string>
<string name="catalyst_performance_background" project="catalyst" translatable="false">Finish performance trace</string>
<string name="catalyst_performance_disabled" project="catalyst" translatable="false">Start performance trace</string>
<string name="catalyst_performance_cdp" project="catalyst" translatable="false">Performance tracing disabled</string>
<string name="catalyst_debug_open_disabled" project="catalyst" translatable="false">Connect to the bundler to debug JavaScript</string>
<string name="catalyst_debug_connecting" project="catalyst" translatable="false">Connecting to debugger...</string>
<string name="catalyst_debug_error" project="catalyst" translatable="false">Failed to connect to debugger!</string>
Expand Down
Loading
Loading