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
1 change: 1 addition & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -3186,6 +3186,7 @@ public final class com/facebook/react/soloader/OpenSourceMergedSoMapping : com/f
public final fun libreact_devsupportjni_so ()I
public final fun libreact_featureflagsjni_so ()I
public final fun libreact_newarchdefaults_so ()I
public final fun libreact_performancetracerjni_so ()I
public final fun libreactnative_so ()I
public final fun libreactnativeblob_so ()I
public final fun libreactnativejni_common_so ()I
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ 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 @@ -211,6 +212,8 @@ 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 @@ -969,12 +972,37 @@ 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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

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

@DoNotStripAny
internal class FrameTiming(private val window: Window) {
init {
SoLoader.loadLibrary("react_devsupportjni")
}

private var frameCounter: Int = 0

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

private val frameMetricsListener =
Window.OnFrameMetricsAvailableListener { _, frameMetrics, dropCount ->
val metrics = FrameMetrics(frameMetrics)

val paintStartTime = metrics.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP)
val totalDuration = metrics.getMetric(FrameMetrics.TOTAL_DURATION)

val currentFrame = frameCounter++
reportFrameTiming(
frame = currentFrame,
paintStartNanos = paintStartTime,
paintEndNanos = paintStartTime + totalDuration,
)
}

companion object {
@JvmStatic
private external fun reportFrameTiming(frame: Int, paintStartNanos: Long, paintEndNanos: Long)
}

private val handler = Handler(Looper.getMainLooper())

internal fun startMonitoring() {
frameCounter = 0
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return
}
window.addOnFrameMetricsAvailableListener(frameMetricsListener, handler)

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

internal fun stopMonitoring() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return
}
window.removeOnFrameMetricsAvailableListener(frameMetricsListener)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping {
"react_devsupportjni",
"react_featureflagsjni",
"react_newarchdefaults",
"react_performancetracerjni",
"reactnativeblob",
"reactnativejni",
"reactnativejni_common",
Expand Down Expand Up @@ -57,6 +58,7 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping {
"react_devsupportjni" -> libreact_devsupportjni_so()
"react_featureflagsjni" -> libreact_featureflagsjni_so()
"react_newarchdefaults" -> libreact_newarchdefaults_so()
"react_performancetracerjni" -> libreact_performancetracerjni_so()
"reactnative" -> libreactnative_so()
"reactnativeblob" -> libreactnativeblob_so()
"reactnativejni" -> libreactnativejni_so()
Expand Down Expand Up @@ -88,6 +90,8 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping {

public external fun libreact_newarchdefaults_so(): Int

public external fun libreact_performancetracerjni_so(): Int

public external fun libreactnative_so(): Int

public external fun libreactnativeblob_so(): Int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ add_react_android_subdir(src/main/jni/react/runtime/cxxreactpackage)
add_react_android_subdir(src/main/jni/react/runtime/jni)
add_react_android_subdir(src/main/jni/react/runtime/hermes/jni)
add_react_android_subdir(src/main/jni/react/devsupport)
add_react_android_subdir(src/main/jni/react/tracing)

# SoMerging Utils
include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake)
Expand Down Expand Up @@ -197,6 +198,7 @@ add_library(reactnative
$<TARGET_OBJECTS:react_newarchdefaults>
$<TARGET_OBJECTS:react_performance_cdpmetrics>
$<TARGET_OBJECTS:react_performance_timeline>
$<TARGET_OBJECTS:react_performancetracerjni>
$<TARGET_OBJECTS:react_renderer_animations>
$<TARGET_OBJECTS:react_renderer_attributedstring>
$<TARGET_OBJECTS:react_renderer_componentregistry>
Expand Down Expand Up @@ -288,6 +290,7 @@ target_include_directories(reactnative
$<TARGET_PROPERTY:react_newarchdefaults,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_performance_cdpmetrics,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_performance_timeline,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_performancetracerjni,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_renderer_animations,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_renderer_attributedstring,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:react_renderer_componentregistry,INTERFACE_INCLUDE_DIRECTORIES>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ target_include_directories(react_devsupportjni PUBLIC .)
target_link_libraries(react_devsupportjni
fbjni
jsinspector
react_networking)
jsinspector_tracing
react_networking
react_timing)

target_compile_reactnative_options(react_devsupportjni PRIVATE)
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.
*/

#include "JFrameTiming.h"

#include <jsinspector-modern/tracing/PerformanceTracer.h>
#include <react/timing/primitives.h>

namespace facebook::react::jsinspector_modern {

void JFrameTiming::reportFrameTiming(
jni::alias_ref<jclass> /*unused*/,
jint frameNumber,
jlong paintStartNanos,
jlong paintEndNanos) {
auto& performanceTracer = tracing::PerformanceTracer::getInstance();

auto startTime = HighResTimeStamp::fromDOMHighResTimeStamp(
static_cast<double>(paintStartNanos) / 1e6);
auto endTime = HighResTimeStamp::fromDOMHighResTimeStamp(
static_cast<double>(paintEndNanos) / 1e6);

performanceTracer.reportFrameTiming(frameNumber, startTime, endTime);
}

void JFrameTiming::setLayerTreeId(
jni::alias_ref<jclass> /*unused*/,
jni::alias_ref<jstring> frame,
jint layerTreeId) {
auto& performanceTracer = tracing::PerformanceTracer::getInstance();

performanceTracer.setLayerTreeId(frame->toStdString(), layerTreeId);
}

void JFrameTiming::registerNatives() {
javaClassLocal()->registerNatives({
makeNativeMethod("reportFrameTiming", JFrameTiming::reportFrameTiming),
makeNativeMethod("setLayerTreeId", JFrameTiming::setLayerTreeId),
});
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.
*/

#pragma once

#include <fbjni/fbjni.h>

namespace facebook::react::jsinspector_modern {

/**
* JNI wrapper for reporting frame timing to PerformanceTracer.
*/
class JFrameTiming : public jni::JavaClass<JFrameTiming> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/FrameTiming;";

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

static void setLayerTreeId(jni::alias_ref<jclass> /*unused*/, jni::alias_ref<jstring> frame, jint layerTreeId);

static void registerNatives();

private:
JFrameTiming() = delete;
};

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "JCxxInspectorPackagerConnection.h"
#include "JCxxInspectorPackagerConnectionWebSocketDelegate.h"
#include "JFrameTiming.h"
#include "JInspectorFlags.h"
#include "JInspectorNetworkReporter.h"

Expand All @@ -18,6 +19,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*unused*/) {
registerNatives();
facebook::react::jsinspector_modern::
JCxxInspectorPackagerConnectionWebSocketDelegate::registerNatives();
facebook::react::jsinspector_modern::JFrameTiming::registerNatives();
facebook::react::jsinspector_modern::JInspectorFlags::registerNatives();
facebook::react::jsinspector_modern::JInspectorNetworkReporter::
registerNatives();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# 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.

cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)

include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)

file(GLOB react_performancetracerjni_SRC CONFIGURE_DEPENDS *.cpp)

add_library(react_performancetracerjni OBJECT ${react_performancetracerjni_SRC})

target_merge_so(react_performancetracerjni)

target_include_directories(react_performancetracerjni PUBLIC .)

target_link_libraries(react_performancetracerjni
fbjni
jsinspector
jsinspector_tracing
reactnativejni_common
react_timing)

target_compile_reactnative_options(react_performancetracerjni PRIVATE)
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,15 @@ void PerformanceTracer::reportFrameTiming(
int frameSeqId,
HighResTimeStamp start,
HighResTimeStamp end) {
if (!tracingAtomic_) {
return;
}

std::lock_guard<std::mutex> lock(mutex_);
if (!tracingAtomic_) {
return;
}

ThreadId threadId = getCurrentThreadId();
enqueueEvent(
PerformanceTracerFrameBeginDrawEvent{
Expand Down
Loading