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
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
import com.facebook.react.devsupport.perfmonitor.PerfMonitorOverlayManager
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
import com.facebook.react.internal.tracing.PerformanceTracer
import com.facebook.react.modules.core.RCTNativeAppEventEmitter
import com.facebook.react.modules.debug.interfaces.DeveloperSettings
import com.facebook.react.packagerconnection.RequestHandler
Expand Down Expand Up @@ -212,8 +211,6 @@ public abstract class DevSupportManagerBase(
private var perfMonitorOverlayManager: PerfMonitorOverlayManager? = null
private var perfMonitorInitialized = false
private var tracingStateProvider: TracingStateProvider? = null
private var tracingStateSubscriptionId: Int? = null
private var frameTiming: FrameTiming? = null

public override var keyboardShortcutsEnabled: Boolean = true
public override var devMenuEnabled: Boolean = true
Expand Down Expand Up @@ -972,37 +969,12 @@ public abstract class DevSupportManagerBase(
isPackagerConnected = true
perfMonitorOverlayManager?.enable()
perfMonitorOverlayManager?.startBackgroundTrace()

// Subscribe to tracing state changes
tracingStateSubscriptionId =
PerformanceTracer.subscribeToTracingStateChanges(
object : PerformanceTracer.TracingStateCallback {
override fun onTracingStateChanged(isTracing: Boolean) {
if (isTracing) {
if (frameTiming == null) {
currentActivity?.window?.let { window ->
frameTiming = FrameTiming(window)
}
}
frameTiming?.startMonitoring()
} else {
frameTiming?.stopMonitoring()
}
}
}
)
}

override fun onPackagerDisconnected() {
isPackagerConnected = false
perfMonitorOverlayManager?.disable()
perfMonitorOverlayManager?.stopBackgroundTrace()

// Unsubscribe from tracing state changes
tracingStateSubscriptionId?.let { subscriptionId ->
PerformanceTracer.unsubscribeFromTracingStateChanges(subscriptionId)
tracingStateSubscriptionId = null
}
}

override fun onPackagerReloadCommand() {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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.inspector

internal data class FrameTimingSequence(
val id: Int,
val threadId: Int,
val beginDrawingTimestamp: Long,
val commitTimestamp: Long,
val endDrawingTimestamp: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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.inspector

import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.Process
import android.view.FrameMetrics
import android.view.Window
import com.facebook.proguard.annotations.DoNotStripAny
import com.facebook.soloader.SoLoader

@DoNotStripAny
internal class FrameTimingsObserver(
private val window: Window,
onFrameTimingSequence: (sequence: FrameTimingSequence) -> Unit,
) {
private val handler = Handler(Looper.getMainLooper())
private var frameCounter: Int = 0

private external fun setLayerTreeId(frame: String, layerTreeId: Int)

private val frameMetricsListener =
Window.OnFrameMetricsAvailableListener { _, frameMetrics, _dropCount ->
val beginDrawingTimestamp = frameMetrics.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP)
val commitTimestamp =
beginDrawingTimestamp + frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)
+frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION)
+frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)
+frameMetrics.getMetric(FrameMetrics.DRAW_DURATION)
+frameMetrics.getMetric(FrameMetrics.SYNC_DURATION)
val endDrawingTimestamp =
beginDrawingTimestamp + frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)

onFrameTimingSequence(
FrameTimingSequence(
frameCounter++,
Process.myTid(),
beginDrawingTimestamp,
commitTimestamp,
endDrawingTimestamp,
)
)
}

fun start() {
frameCounter = 0
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return
}

window.addOnFrameMetricsAvailableListener(frameMetricsListener, handler)
}

fun stop() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return
}

window.removeOnFrameMetricsAvailableListener(frameMetricsListener)
handler.removeCallbacksAndMessages(null)
}

private companion object {
init {
SoLoader.loadLibrary("react_devsupportjni")
}

@JvmStatic
private external fun reportFrameTiming(frame: Int, paintStartNanos: Long, paintEndNanos: Long)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ import com.facebook.react.devsupport.DevMenuConfiguration
import com.facebook.react.devsupport.DevSupportManagerBase
import com.facebook.react.devsupport.DevSupportManagerFactory
import com.facebook.react.devsupport.InspectorFlags
import com.facebook.react.devsupport.inspector.FrameTimingsObserver
import com.facebook.react.devsupport.inspector.InspectorNetworkHelper
import com.facebook.react.devsupport.inspector.InspectorNetworkRequestListener
import com.facebook.react.devsupport.inspector.TracingState
import com.facebook.react.devsupport.inspector.TracingStateListener
import com.facebook.react.devsupport.interfaces.BundleLoadCallback
import com.facebook.react.devsupport.interfaces.DevSupportManager
import com.facebook.react.devsupport.interfaces.DevSupportManager.PausedInDebuggerOverlayCommandListener
Expand Down Expand Up @@ -147,6 +150,7 @@ public class ReactHostImpl(
private val beforeDestroyListeners: MutableList<() -> Unit> = CopyOnWriteArrayList()

internal var reactHostInspectorTarget: ReactHostInspectorTarget? = null
private var frameTimingsObserver: FrameTimingsObserver? = null

@Volatile private var hostInvalidated = false

Expand Down Expand Up @@ -1442,8 +1446,7 @@ public class ReactHostImpl(
// If the host has been invalidated, now that the current context/instance
// has been unregistered, we can safely destroy the host's inspector
// target.
reactHostInspectorTarget?.close()
reactHostInspectorTarget = null
destroyReactHostInspectorTarget()
}

// Step 1: Destroy DevSupportManager
Expand Down Expand Up @@ -1554,13 +1557,48 @@ public class ReactHostImpl(

internal fun getOrCreateReactHostInspectorTarget(): ReactHostInspectorTarget? {
if (reactHostInspectorTarget == null && InspectorFlags.getFuseboxEnabled()) {
// NOTE: ReactHostInspectorTarget only retains a weak reference to `this`.
reactHostInspectorTarget = ReactHostInspectorTarget(this)
reactHostInspectorTarget = createReactHostInspectorTarget()
}

return reactHostInspectorTarget
}

private fun createReactHostInspectorTarget(): ReactHostInspectorTarget {
// NOTE: ReactHostInspectorTarget only retains a weak reference to `this`.
val inspectorTarget = ReactHostInspectorTarget(this)
inspectorTarget.registerTracingStateListener(
TracingStateListener { state: TracingState, _screenshotsEnabled: Boolean ->
when (state) {
TracingState.ENABLED_IN_BACKGROUND_MODE,
TracingState.ENABLED_IN_CDP_MODE -> {
currentActivity?.window?.let { window ->
val observer =
FrameTimingsObserver(window) { frameTimingsSequence ->
inspectorTarget.recordFrameTimings(frameTimingsSequence)
}
observer.start()
frameTimingsObserver = observer
}
}
TracingState.DISABLED -> {
frameTimingsObserver?.stop()
frameTimingsObserver = null
}
}
}
)

return inspectorTarget
}

private fun destroyReactHostInspectorTarget() {
frameTimingsObserver?.stop()
frameTimingsObserver = null

reactHostInspectorTarget?.close()
reactHostInspectorTarget = null
}

@ThreadConfined(ThreadConfined.UI)
internal fun unregisterInstanceFromInspector(reactInstance: ReactInstance?) {
if (reactInstance != null) {
Expand Down
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.inspector.FrameTimingSequence
import com.facebook.react.devsupport.inspector.TracingState
import com.facebook.react.devsupport.inspector.TracingStateListener
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTarget
Expand Down Expand Up @@ -48,6 +49,8 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) :

external fun unregisterTracingStateListener(subscriptionId: Long)

external fun recordFrameTimings(frameTimingSequence: FrameTimingSequence)

override fun addPerfMonitorListener(listener: PerfMonitorUpdateListener) {
perfMonitorListeners.add(listener)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace facebook::react::jsinspector_modern {
*/
class JFrameTiming : public jni::JavaClass<JFrameTiming> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/FrameTiming;";
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/inspector/FrameTimingsObserver;";

static void
reportFrameTiming(jni::alias_ref<jclass> /*unused*/, jint frame, jlong paintStartNanos, jlong paintEndNanos);
Expand Down
Loading