Skip to content

Commit 65b1eb3

Browse files
hoxyqmeta-codesync[bot]
authored andcommitted
FrameTiming module to subscribe to Inspector tracing lifecycle (facebook#54633)
Summary: Pull Request resolved: facebook#54633 # Changelog: [Internal] This introduces a proper lifecycle for a module on Anroid that will emit frames information as part of the trace recording. Previously we would initialize it on a packager connection, which could be problematic, since there is no guarantee that InspectorTarget exists at this time. With the current approach, the lifetime of this object is: - Bound to lifetime of InspectorTarget, it will never outlive it - The actual frames listener lifetime will be bound to tracing state. We no longer will be going through `jni` to check if `PerformanceTracer` is enabled. I've renamed it to `FrameTimingsObserver`and moved to inspector package, since this should be considered as part of the inspector stack. Similarly to `LoadNetworkResource` listeners. I am keeping the `jni` layer with PerformanceTracer for now, but this is about to be removed in the diffs above. The frames information should be propagated through Host, this would allow us to record Frames even if there is no React Native instance, for example, during reloads. Reviewed By: sbuggay Differential Revision: D87345177
1 parent 4c560b1 commit 65b1eb3

File tree

4 files changed

+57
-48
lines changed

4 files changed

+57
-48
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
7272
import com.facebook.react.devsupport.perfmonitor.PerfMonitorOverlayManager
7373
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
7474
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
75-
import com.facebook.react.internal.tracing.PerformanceTracer
7675
import com.facebook.react.modules.core.RCTNativeAppEventEmitter
7776
import com.facebook.react.modules.debug.interfaces.DeveloperSettings
7877
import com.facebook.react.packagerconnection.RequestHandler
@@ -212,8 +211,6 @@ public abstract class DevSupportManagerBase(
212211
private var perfMonitorOverlayManager: PerfMonitorOverlayManager? = null
213212
private var perfMonitorInitialized = false
214213
private var tracingStateProvider: TracingStateProvider? = null
215-
private var tracingStateSubscriptionId: Int? = null
216-
private var frameTiming: FrameTiming? = null
217214

218215
public override var keyboardShortcutsEnabled: Boolean = true
219216
public override var devMenuEnabled: Boolean = true
@@ -972,37 +969,12 @@ public abstract class DevSupportManagerBase(
972969
isPackagerConnected = true
973970
perfMonitorOverlayManager?.enable()
974971
perfMonitorOverlayManager?.startBackgroundTrace()
975-
976-
// Subscribe to tracing state changes
977-
tracingStateSubscriptionId =
978-
PerformanceTracer.subscribeToTracingStateChanges(
979-
object : PerformanceTracer.TracingStateCallback {
980-
override fun onTracingStateChanged(isTracing: Boolean) {
981-
if (isTracing) {
982-
if (frameTiming == null) {
983-
currentActivity?.window?.let { window ->
984-
frameTiming = FrameTiming(window)
985-
}
986-
}
987-
frameTiming?.startMonitoring()
988-
} else {
989-
frameTiming?.stopMonitoring()
990-
}
991-
}
992-
}
993-
)
994972
}
995973

996974
override fun onPackagerDisconnected() {
997975
isPackagerConnected = false
998976
perfMonitorOverlayManager?.disable()
999977
perfMonitorOverlayManager?.stopBackgroundTrace()
1000-
1001-
// Unsubscribe from tracing state changes
1002-
tracingStateSubscriptionId?.let { subscriptionId ->
1003-
PerformanceTracer.unsubscribeFromTracingStateChanges(subscriptionId)
1004-
tracingStateSubscriptionId = null
1005-
}
1006978
}
1007979

1008980
override fun onPackagerReloadCommand() {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/FrameTiming.kt renamed to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
package com.facebook.react.devsupport
8+
package com.facebook.react.devsupport.inspector
99

1010
import android.os.Build
1111
import android.os.Handler
@@ -16,11 +16,8 @@ import com.facebook.proguard.annotations.DoNotStripAny
1616
import com.facebook.soloader.SoLoader
1717

1818
@DoNotStripAny
19-
internal class FrameTiming(private val window: Window) {
20-
init {
21-
SoLoader.loadLibrary("react_devsupportjni")
22-
}
23-
19+
internal class FrameTimingsObserver(private val window: Window) {
20+
private val handler = Handler(Looper.getMainLooper())
2421
private var frameCounter: Int = 0
2522

2623
private external fun setLayerTreeId(frame: String, layerTreeId: Int)
@@ -40,29 +37,34 @@ internal class FrameTiming(private val window: Window) {
4037
)
4138
}
4239

43-
companion object {
44-
@JvmStatic
45-
private external fun reportFrameTiming(frame: Int, paintStartNanos: Long, paintEndNanos: Long)
46-
}
47-
48-
private val handler = Handler(Looper.getMainLooper())
49-
50-
internal fun startMonitoring() {
40+
fun start() {
5141
frameCounter = 0
5242
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
5343
return
5444
}
45+
5546
window.addOnFrameMetricsAvailableListener(frameMetricsListener, handler)
5647

5748
// Hardcoded frame identfier and layerTreeId. Needed for DevTools to
5849
// begin parsing frame events.
5950
setLayerTreeId("", 1)
6051
}
6152

62-
internal fun stopMonitoring() {
53+
fun stop() {
6354
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
6455
return
6556
}
57+
6658
window.removeOnFrameMetricsAvailableListener(frameMetricsListener)
59+
handler.removeCallbacksAndMessages(null)
60+
}
61+
62+
private companion object {
63+
init {
64+
SoLoader.loadLibrary("react_devsupportjni")
65+
}
66+
67+
@JvmStatic
68+
private external fun reportFrameTiming(frame: Int, paintStartNanos: Long, paintEndNanos: Long)
6769
}
6870
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ import com.facebook.react.devsupport.DevMenuConfiguration
4343
import com.facebook.react.devsupport.DevSupportManagerBase
4444
import com.facebook.react.devsupport.DevSupportManagerFactory
4545
import com.facebook.react.devsupport.InspectorFlags
46+
import com.facebook.react.devsupport.inspector.FrameTimingsObserver
4647
import com.facebook.react.devsupport.inspector.InspectorNetworkHelper
4748
import com.facebook.react.devsupport.inspector.InspectorNetworkRequestListener
49+
import com.facebook.react.devsupport.inspector.TracingState
50+
import com.facebook.react.devsupport.inspector.TracingStateListener
4851
import com.facebook.react.devsupport.interfaces.BundleLoadCallback
4952
import com.facebook.react.devsupport.interfaces.DevSupportManager
5053
import com.facebook.react.devsupport.interfaces.DevSupportManager.PausedInDebuggerOverlayCommandListener
@@ -147,6 +150,7 @@ public class ReactHostImpl(
147150
private val beforeDestroyListeners: MutableList<() -> Unit> = CopyOnWriteArrayList()
148151

149152
internal var reactHostInspectorTarget: ReactHostInspectorTarget? = null
153+
private var frameTimingsObserver: FrameTimingsObserver? = null
150154

151155
@Volatile private var hostInvalidated = false
152156

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

14491452
// Step 1: Destroy DevSupportManager
@@ -1554,13 +1557,45 @@ public class ReactHostImpl(
15541557

15551558
internal fun getOrCreateReactHostInspectorTarget(): ReactHostInspectorTarget? {
15561559
if (reactHostInspectorTarget == null && InspectorFlags.getFuseboxEnabled()) {
1557-
// NOTE: ReactHostInspectorTarget only retains a weak reference to `this`.
1558-
reactHostInspectorTarget = ReactHostInspectorTarget(this)
1560+
reactHostInspectorTarget = createReactHostInspectorTarget()
15591561
}
15601562

15611563
return reactHostInspectorTarget
15621564
}
15631565

1566+
private fun createReactHostInspectorTarget(): ReactHostInspectorTarget {
1567+
// NOTE: ReactHostInspectorTarget only retains a weak reference to `this`.
1568+
val inspectorTarget = ReactHostInspectorTarget(this)
1569+
inspectorTarget.registerTracingStateListener(
1570+
TracingStateListener { state: TracingState, _screenshotsEnabled: Boolean ->
1571+
when (state) {
1572+
TracingState.ENABLED_IN_BACKGROUND_MODE,
1573+
TracingState.ENABLED_IN_CDP_MODE -> {
1574+
currentActivity?.window?.let { window ->
1575+
val observer = FrameTimingsObserver(window)
1576+
observer.start()
1577+
frameTimingsObserver = observer
1578+
}
1579+
}
1580+
TracingState.DISABLED -> {
1581+
frameTimingsObserver?.stop()
1582+
frameTimingsObserver = null
1583+
}
1584+
}
1585+
}
1586+
)
1587+
1588+
return inspectorTarget
1589+
}
1590+
1591+
private fun destroyReactHostInspectorTarget() {
1592+
frameTimingsObserver?.stop()
1593+
frameTimingsObserver = null
1594+
1595+
reactHostInspectorTarget?.close()
1596+
reactHostInspectorTarget = null
1597+
}
1598+
15641599
@ThreadConfined(ThreadConfined.UI)
15651600
internal fun unregisterInstanceFromInspector(reactInstance: ReactInstance?) {
15661601
if (reactInstance != null) {

packages/react-native/ReactAndroid/src/main/jni/react/devsupport/JFrameTiming.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace facebook::react::jsinspector_modern {
1616
*/
1717
class JFrameTiming : public jni::JavaClass<JFrameTiming> {
1818
public:
19-
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/FrameTiming;";
19+
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/inspector/FrameTimingsObserver;";
2020

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

0 commit comments

Comments
 (0)