Last active
April 9, 2026 10:28
-
-
Save huntie/9b034059245205f425da600cdbb38f23 to your computer and use it in GitHub Desktop.
backport-perf-trace-vs-main.diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/packages/react-native/React/DevSupport/RCTFrameTimingsObserver.mm b/packages/react-native/React/DevSupport/RCTFrameTimingsObserver.mm | |
| index ec9a0ae01fb..112bba1fc06 100644 | |
| --- a/packages/react-native/React/DevSupport/RCTFrameTimingsObserver.mm | |
| +++ b/packages/react-native/React/DevSupport/RCTFrameTimingsObserver.mm | |
| @@ -14,7 +14,6 @@ | |
| #import <atomic> | |
| #import <chrono> | |
| -#import <mutex> | |
| #import <optional> | |
| #import <vector> | |
| @@ -22,41 +21,17 @@ | |
| using namespace facebook::react; | |
| -static constexpr CGFloat kScreenshotScaleFactor = 1.0; | |
| +static constexpr CGFloat kScreenshotScaleFactor = 0.75; | |
| static constexpr CGFloat kScreenshotJPEGQuality = 0.8; | |
| -namespace { | |
| - | |
| -// Stores a captured frame screenshot and its associated metadata, used for | |
| -// buffering frames during dynamic sampling. | |
| -struct FrameData { | |
| - UIImage *image; | |
| - uint64_t frameId; | |
| - jsinspector_modern::tracing::ThreadId threadId; | |
| - HighResTimeStamp beginTimestamp; | |
| - HighResTimeStamp endTimestamp; | |
| -}; | |
| - | |
| -} // namespace | |
| - | |
| @implementation RCTFrameTimingsObserver { | |
| BOOL _screenshotsEnabled; | |
| RCTFrameTimingCallback _callback; | |
| CADisplayLink *_displayLink; | |
| uint64_t _frameCounter; | |
| - // Serial queue for encoding work (single background thread). We limit to 1 | |
| - // thread to minimize the performance impact of screenshot recording. | |
| dispatch_queue_t _encodingQueue; | |
| std::atomic<bool> _running; | |
| uint64_t _lastScreenshotHash; | |
| - | |
| - // Stores the most recently captured frame to opportunistically encode after | |
| - // the current frame. Replaced frames are emitted as timings without | |
| - // screenshots. | |
| - std::mutex _lastFrameMutex; | |
| - std::optional<FrameData> _lastFrameData; | |
| - | |
| - std::atomic<bool> _encodingInProgress; | |
| } | |
| - (instancetype)initWithScreenshotsEnabled:(BOOL)screenshotsEnabled callback:(RCTFrameTimingCallback)callback | |
| @@ -68,7 +43,6 @@ struct FrameData { | |
| _encodingQueue = dispatch_queue_create("com.facebook.react.frame-timings-observer", DISPATCH_QUEUE_SERIAL); | |
| _running.store(false); | |
| _lastScreenshotHash = 0; | |
| - _encodingInProgress.store(false); | |
| } | |
| return self; | |
| } | |
| @@ -78,13 +52,9 @@ struct FrameData { | |
| _running.store(true, std::memory_order_relaxed); | |
| _frameCounter = 0; | |
| _lastScreenshotHash = 0; | |
| - _encodingInProgress.store(false, std::memory_order_relaxed); | |
| - { | |
| - std::lock_guard<std::mutex> lock(_lastFrameMutex); | |
| - _lastFrameData.reset(); | |
| - } | |
| - // Emit initial frame event | |
| + // Emit an initial frame timing to ensure at least one frame is captured at the | |
| + // start of tracing, even if no UI changes occur. | |
| auto now = HighResTimeStamp::now(); | |
| [self _emitFrameTimingWithBeginTimestamp:now endTimestamp:now]; | |
| @@ -97,10 +67,6 @@ struct FrameData { | |
| _running.store(false, std::memory_order_relaxed); | |
| [_displayLink invalidate]; | |
| _displayLink = nil; | |
| - { | |
| - std::lock_guard<std::mutex> lock(_lastFrameMutex); | |
| - _lastFrameData.reset(); | |
| - } | |
| } | |
| - (void)_displayLinkTick:(CADisplayLink *)sender | |
| @@ -124,115 +90,32 @@ struct FrameData { | |
| uint64_t frameId = _frameCounter++; | |
| auto threadId = static_cast<jsinspector_modern::tracing::ThreadId>(pthread_mach_thread_np(pthread_self())); | |
| - if (!_screenshotsEnabled) { | |
| - // Screenshots disabled - emit without screenshot | |
| - [self _emitFrameEventWithFrameId:frameId | |
| - threadId:threadId | |
| - beginTimestamp:beginTimestamp | |
| - endTimestamp:endTimestamp | |
| - screenshot:std::nullopt]; | |
| - return; | |
| - } | |
| - | |
| - UIImage *image = [self _captureScreenshot]; | |
| - if (image == nil) { | |
| - // Failed to capture (e.g. no window, duplicate hash) - emit without screenshot | |
| - [self _emitFrameEventWithFrameId:frameId | |
| - threadId:threadId | |
| - beginTimestamp:beginTimestamp | |
| - endTimestamp:endTimestamp | |
| - screenshot:std::nullopt]; | |
| - return; | |
| - } | |
| - | |
| - FrameData frameData{image, frameId, threadId, beginTimestamp, endTimestamp}; | |
| - | |
| - bool expected = false; | |
| - if (_encodingInProgress.compare_exchange_strong(expected, true)) { | |
| - // Not encoding - encode this frame immediately | |
| - [self _encodeFrame:std::move(frameData)]; | |
| + if (_screenshotsEnabled) { | |
| + [self _captureScreenshotWithCompletion:^(std::optional<std::vector<uint8_t>> screenshotData) { | |
| + if (!self->_running.load()) { | |
| + return; | |
| + } | |
| + jsinspector_modern::tracing::FrameTimingSequence sequence{ | |
| + frameId, threadId, beginTimestamp, endTimestamp, std::move(screenshotData)}; | |
| + self->_callback(std::move(sequence)); | |
| + }]; | |
| } else { | |
| - // Encoding thread busy - store current screenshot in buffer for tail-capture | |
| - std::optional<FrameData> oldFrame; | |
| - { | |
| - std::lock_guard<std::mutex> lock(_lastFrameMutex); | |
| - oldFrame = std::move(_lastFrameData); | |
| - _lastFrameData = std::move(frameData); | |
| - } | |
| - if (oldFrame.has_value()) { | |
| - // Skipped frame - emit event without screenshot | |
| - [self _emitFrameEventWithFrameId:oldFrame->frameId | |
| - threadId:oldFrame->threadId | |
| - beginTimestamp:oldFrame->beginTimestamp | |
| - endTimestamp:oldFrame->endTimestamp | |
| - screenshot:std::nullopt]; | |
| - } | |
| - } | |
| -} | |
| - | |
| -- (void)_emitFrameEventWithFrameId:(uint64_t)frameId | |
| - threadId:(jsinspector_modern::tracing::ThreadId)threadId | |
| - beginTimestamp:(HighResTimeStamp)beginTimestamp | |
| - endTimestamp:(HighResTimeStamp)endTimestamp | |
| - screenshot:(std::optional<std::vector<uint8_t>>)screenshot | |
| -{ | |
| - dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ | |
| - if (!self->_running.load(std::memory_order_relaxed)) { | |
| - return; | |
| - } | |
| - jsinspector_modern::tracing::FrameTimingSequence sequence{ | |
| - frameId, threadId, beginTimestamp, endTimestamp, std::move(screenshot)}; | |
| - self->_callback(std::move(sequence)); | |
| - }); | |
| -} | |
| - | |
| -- (void)_encodeFrame:(FrameData)frameData | |
| -{ | |
| - dispatch_async(_encodingQueue, ^{ | |
| - if (!self->_running.load(std::memory_order_relaxed)) { | |
| - return; | |
| - } | |
| - | |
| - auto screenshot = [self _encodeScreenshot:frameData.image]; | |
| - [self _emitFrameEventWithFrameId:frameData.frameId | |
| - threadId:frameData.threadId | |
| - beginTimestamp:frameData.beginTimestamp | |
| - endTimestamp:frameData.endTimestamp | |
| - screenshot:std::move(screenshot)]; | |
| - | |
| - // Clear encoding flag early, allowing new frames to start fresh encoding | |
| - // sessions | |
| - self->_encodingInProgress.store(false, std::memory_order_release); | |
| - | |
| - // Opportunistically encode tail frame (if present) without blocking new | |
| - // frames | |
| - std::optional<FrameData> tailFrame; | |
| - { | |
| - std::lock_guard<std::mutex> lock(self->_lastFrameMutex); | |
| - tailFrame = std::move(self->_lastFrameData); | |
| - self->_lastFrameData.reset(); | |
| - } | |
| - if (tailFrame.has_value()) { | |
| + dispatch_async(_encodingQueue, ^{ | |
| if (!self->_running.load(std::memory_order_relaxed)) { | |
| return; | |
| } | |
| - auto tailScreenshot = [self _encodeScreenshot:tailFrame->image]; | |
| - [self _emitFrameEventWithFrameId:tailFrame->frameId | |
| - threadId:tailFrame->threadId | |
| - beginTimestamp:tailFrame->beginTimestamp | |
| - endTimestamp:tailFrame->endTimestamp | |
| - screenshot:std::move(tailScreenshot)]; | |
| - } | |
| - }); | |
| + jsinspector_modern::tracing::FrameTimingSequence sequence{frameId, threadId, beginTimestamp, endTimestamp}; | |
| + self->_callback(std::move(sequence)); | |
| + }); | |
| + } | |
| } | |
| -// Captures a screenshot of the current window. Must be called on the main | |
| -// thread. Returns nil if capture fails or if the frame content is unchanged. | |
| -- (UIImage *)_captureScreenshot | |
| +- (void)_captureScreenshotWithCompletion:(void (^)(std::optional<std::vector<uint8_t>>))completion | |
| { | |
| UIWindow *keyWindow = [self _getKeyWindow]; | |
| - if (keyWindow == nil) { | |
| - return nil; | |
| + if (keyWindow == nullptr) { | |
| + completion(std::nullopt); | |
| + return; | |
| } | |
| UIView *rootView = keyWindow.rootViewController.view ?: keyWindow; | |
| @@ -261,22 +144,24 @@ struct FrameData { | |
| CFRelease(pixelData); | |
| if (hash == _lastScreenshotHash) { | |
| - return nil; | |
| + return; | |
| } | |
| _lastScreenshotHash = hash; | |
| - return image; | |
| -} | |
| - | |
| -- (std::optional<std::vector<uint8_t>>)_encodeScreenshot:(UIImage *)image | |
| -{ | |
| - NSData *jpegData = UIImageJPEGRepresentation(image, kScreenshotJPEGQuality); | |
| - if (jpegData == nil) { | |
| - return std::nullopt; | |
| - } | |
| + dispatch_async(_encodingQueue, ^{ | |
| + if (!self->_running.load(std::memory_order_relaxed)) { | |
| + return; | |
| + } | |
| + NSData *jpegData = UIImageJPEGRepresentation(image, kScreenshotJPEGQuality); | |
| + if (jpegData == nullptr) { | |
| + completion(std::nullopt); | |
| + return; | |
| + } | |
| - const auto *bytes = static_cast<const uint8_t *>(jpegData.bytes); | |
| - return std::vector<uint8_t>(bytes, bytes + jpegData.length); | |
| + const auto *bytes = static_cast<const uint8_t *>(jpegData.bytes); | |
| + std::vector<uint8_t> screenshotBytes(bytes, bytes + jpegData.length); | |
| + completion(std::move(screenshotBytes)); | |
| + }); | |
| } | |
| - (UIWindow *)_getKeyWindow | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt | |
| index 06aeeea9fc3..9679ea67c2f 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt | |
| @@ -23,8 +23,9 @@ import com.facebook.react.packagerconnection.RequestHandler | |
| * [DevSupportManagerBase] with some additional, more flexible APIs for asynchronously loading the | |
| * JS bundle. | |
| * | |
| - * @constructor The primary constructor mirrors the same constructor we had for | |
| - * `BridgeDevSupportManager` and is kept for backward compatibility. | |
| + * @constructor The primary constructor mirrors the same constructor we have for | |
| + * [BridgeDevSupportManager] and | |
| + * * is kept for backward compatibility. | |
| */ | |
| internal class BridgelessDevSupportManager( | |
| applicationContext: Context, | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt | |
| index 0608c07b78b..543ed13f937 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt | |
| @@ -789,8 +789,8 @@ public abstract class DevSupportManagerBase( | |
| callback.onSuccess(bundleLoader) | |
| } | |
| - override fun onProgress(status: String?, done: Int?, total: Int?, percent: Int?) { | |
| - devLoadingViewManager?.updateProgress(status, done, total, percent) | |
| + override fun onProgress(status: String?, done: Int?, total: Int?) { | |
| + devLoadingViewManager?.updateProgress(status, done, total) | |
| } | |
| override fun onFailure(cause: Exception) { | |
| @@ -856,9 +856,9 @@ public abstract class DevSupportManagerBase( | |
| callback.onSuccess() | |
| } | |
| - override fun onProgress(status: String?, done: Int?, total: Int?, percent: Int?) { | |
| - devLoadingViewManager?.updateProgress(status, done, total, percent) | |
| - devBundleDownloadListener?.onProgress(status, done, total, percent) | |
| + override fun onProgress(status: String?, done: Int?, total: Int?) { | |
| + devLoadingViewManager?.updateProgress(status, done, total) | |
| + devBundleDownloadListener?.onProgress(status, done, total) | |
| } | |
| override fun onFailure(cause: Exception) { | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt | |
| index f9e38dda2c5..c7ffcff620a 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt | |
| @@ -9,10 +9,8 @@ package com.facebook.react.devsupport | |
| import com.facebook.proguard.annotations.DoNotStrip | |
| import com.facebook.soloader.SoLoader | |
| -import com.facebook.soloader.annotation.SoLoaderLibrary | |
| /** JNI wrapper for `jsinspector_modern::InspectorFlags`. */ | |
| -@SoLoaderLibrary("react_devsupportjni") | |
| @DoNotStrip | |
| internal object InspectorFlags { | |
| init { | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt | |
| index a88ef73aa95..a6233999023 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt | |
| @@ -97,15 +97,16 @@ internal class FrameTimingsObserver( | |
| } | |
| } | |
| - private val frameMetricsListener = Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ -> | |
| - // Guard against calls after stop() | |
| - if (!isTracing) { | |
| - return@OnFrameMetricsAvailableListener | |
| - } | |
| - val beginTimestamp = frameMetrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP) | |
| - val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION) | |
| - emitFrameTiming(beginTimestamp, endTimestamp) | |
| - } | |
| + private val frameMetricsListener = | |
| + Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ -> | |
| + // Guard against calls after stop() | |
| + if (!isTracing) { | |
| + return@OnFrameMetricsAvailableListener | |
| + } | |
| + val beginTimestamp = frameMetrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP) | |
| + val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION) | |
| + emitFrameTiming(beginTimestamp, endTimestamp) | |
| + } | |
| private fun emitFrameTiming(beginTimestamp: Long, endTimestamp: Long) { | |
| val frameId = frameCounter++ | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt | |
| index 6c550c5a17d..87fe0a92943 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt | |
| @@ -7,8 +7,6 @@ | |
| package com.facebook.react.devsupport.perfmonitor | |
| -import android.os.Handler | |
| -import android.os.Looper | |
| import com.facebook.react.bridge.UiThreadUtil | |
| import com.facebook.react.devsupport.inspector.TracingState | |
| @@ -25,7 +23,6 @@ internal class PerfMonitorOverlayManager( | |
| private var view: PerfMonitorOverlayView? = null | |
| private var tracingState: TracingState = TracingState.ENABLED_IN_CDP_MODE | |
| private var perfIssueCount: Int = 0 | |
| - private val handler = Handler(Looper.getMainLooper()) | |
| /** Enable the Perf Monitor overlay. */ | |
| fun enable() { | |
| @@ -78,37 +75,19 @@ internal class PerfMonitorOverlayManager( | |
| tracingState = state | |
| if (state != TracingState.DISABLED) { | |
| perfIssueCount = 0 | |
| - handler.removeCallbacksAndMessages(null) | |
| } | |
| UiThreadUtil.runOnUiThread { | |
| view?.updateRecordingState(state) | |
| view?.updatePerfIssueCount(perfIssueCount) | |
| - if (state == TracingState.ENABLED_IN_CDP_MODE) { | |
| - view?.hide() | |
| - } else { | |
| - view?.show() | |
| - } | |
| + view?.show() | |
| } | |
| } | |
| override fun onPerfIssueAdded(name: String) { | |
| - perfIssueCount++ | |
| - | |
| UiThreadUtil.runOnUiThread { | |
| - view?.updatePerfIssueCount(perfIssueCount) | |
| + view?.updatePerfIssueCount(++perfIssueCount) | |
| view?.show() | |
| } | |
| - | |
| - handler.postDelayed( | |
| - { | |
| - perfIssueCount-- | |
| - UiThreadUtil.runOnUiThread { | |
| - view?.updatePerfIssueCount(perfIssueCount) | |
| - view?.show() | |
| - } | |
| - }, | |
| - PERF_ISSUE_EXPIRY_MS, | |
| - ) | |
| } | |
| private fun handleRecordingButtonPress() { | |
| @@ -126,8 +105,4 @@ internal class PerfMonitorOverlayManager( | |
| TracingState.ENABLED_IN_CDP_MODE -> Unit | |
| } | |
| } | |
| - | |
| - companion object { | |
| - private const val PERF_ISSUE_EXPIRY_MS = 20_000L | |
| - } | |
| } | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt | |
| index 63d5fa858d4..5f1ce5a89c5 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt | |
| @@ -120,12 +120,12 @@ internal class PerfMonitorOverlayView( | |
| setTextColor(Color.WHITE) | |
| typeface = TYPEFACE_BOLD | |
| val alertDrawable = | |
| - context.getDrawable(R.drawable.ic_perf_issue)?.apply { | |
| + context.getDrawable(android.R.drawable.ic_dialog_alert)?.apply { | |
| setBounds( | |
| 0, | |
| 1, | |
| - dpToPx(ISSUE_ICON_SIZE).toInt(), | |
| - dpToPx(ISSUE_ICON_SIZE).toInt() + 1, | |
| + dpToPx(TEXT_SIZE_PRIMARY).toInt(), | |
| + dpToPx(TEXT_SIZE_PRIMARY).toInt() + 1, | |
| ) | |
| } | |
| setCompoundDrawables(alertDrawable, null, null, null) | |
| @@ -142,9 +142,8 @@ internal class PerfMonitorOverlayView( | |
| val dialog = | |
| createAnchoredDialog(dpToPx(12f), dpToPx(12f)).apply { setContentView(containerLayout) } | |
| dialog.window?.apply { | |
| - attributes = attributes?.apply { | |
| - flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | |
| - } | |
| + attributes = | |
| + attributes?.apply { flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE } | |
| } | |
| return dialog | |
| @@ -159,13 +158,14 @@ internal class PerfMonitorOverlayView( | |
| setCancelable(false) | |
| } | |
| dialog.window?.apply { | |
| - attributes = attributes?.apply { | |
| - width = WindowManager.LayoutParams.WRAP_CONTENT | |
| - height = WindowManager.LayoutParams.WRAP_CONTENT | |
| - gravity = Gravity.TOP or Gravity.END | |
| - x = offsetX.toInt() | |
| - y = offsetY.toInt() | |
| - } | |
| + attributes = | |
| + attributes?.apply { | |
| + width = WindowManager.LayoutParams.WRAP_CONTENT | |
| + height = WindowManager.LayoutParams.WRAP_CONTENT | |
| + gravity = Gravity.TOP or Gravity.END | |
| + x = offsetX.toInt() | |
| + y = offsetY.toInt() | |
| + } | |
| } | |
| dialog.window?.decorView?.let { decorView -> | |
| ViewCompat.setOnApplyWindowInsetsListener(decorView) { view, windowInsets -> | |
| @@ -214,7 +214,6 @@ internal class PerfMonitorOverlayView( | |
| private val COLOR_OVERLAY_BORDER = Color.parseColor("#6C6C6C") | |
| private val TEXT_SIZE_PRIMARY = 12f | |
| private val TEXT_SIZE_ACCESSORY = 10f | |
| - private val ISSUE_ICON_SIZE = 15f | |
| private val TYPEFACE_BOLD = Typeface.create("sans-serif", Typeface.BOLD) | |
| } | |
| } | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt | |
| index c8abc7bb385..8bac4f57c38 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt | |
| @@ -20,7 +20,7 @@ import com.facebook.soloader.SoLoader | |
| @DoNotStrip | |
| public object PerformanceTracer { | |
| init { | |
| - SoLoader.loadLibrary("react_tracingjni") | |
| + SoLoader.loadLibrary("react_performancetracerjni") | |
| } | |
| public fun <T> trace(name: String, block: () -> T): T { | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt | |
| index 5f8b3dd9c18..48ae99d9335 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt | |
| @@ -1027,10 +1027,11 @@ public class ReactHostImpl( | |
| jsBundleLoader.onSuccess( | |
| { task -> | |
| val bundleLoader = checkNotNull(task.getResult()) | |
| - val reactContext = bridgelessReactContextRef.getOrCreate { | |
| - stateTracker.enterState(method, "Creating BridgelessReactContext") | |
| - BridgelessReactContext(context, this) | |
| - } | |
| + val reactContext = | |
| + bridgelessReactContextRef.getOrCreate { | |
| + stateTracker.enterState(method, "Creating BridgelessReactContext") | |
| + BridgelessReactContext(context, this) | |
| + } | |
| reactContext.jsExceptionHandler = devSupportManager | |
| stateTracker.enterState(method, "Creating ReactInstance") | |
| @@ -1305,6 +1306,10 @@ public class ReactHostImpl( | |
| val method = "getOrCreateReloadTask()" | |
| stateTracker.enterState(method) | |
| + // Log how React Native is destroyed | |
| + // TODO(T136397487): Remove after Venice is shipped to 100% | |
| + raiseSoftException(method, reason) | |
| + | |
| reloadTask?.let { | |
| return it | |
| } | |
| @@ -1456,6 +1461,10 @@ public class ReactHostImpl( | |
| val method = "getOrCreateDestroyTask()" | |
| stateTracker.enterState(method) | |
| + // Log how React Native is destroyed | |
| + // TODO(T136397487): Remove after Venice is shipped to 100% | |
| + raiseSoftException(method, reason, ex) | |
| + | |
| destroyTask?.let { | |
| return it | |
| } | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt | |
| index d293887d6c6..322bbb81376 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt | |
| @@ -70,14 +70,7 @@ internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) : | |
| } | |
| override fun destroyRootView(rootView: View) { | |
| - val surface = (rootView as? ReactSurfaceView)?.surface ?: return | |
| - // stop() synchronously removes the surface from ReactHostImpl.attachedSurfaces via | |
| - // detachSurface(), then asynchronously tears down the React component tree. | |
| - // detach() severs the surface's back-reference to the host. | |
| - // clear() removes child views from the ReactSurfaceView. | |
| - surface.stop() | |
| - surface.detach() | |
| - surface.clear() | |
| + // Not implemented, only referenced by BridgeDevSupportManager | |
| } | |
| override fun reload(reason: String) { | |
| diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt | |
| index 936bcac115c..68fb8a8945d 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt | |
| +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt | |
| @@ -41,7 +41,7 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) : | |
| external fun stopAndMaybeEmitBackgroundTrace(): Boolean | |
| - external fun stopTracing() | |
| + external fun stopAndDiscardBackgroundTrace() | |
| external override fun getTracingState(): TracingState | |
| @@ -53,19 +53,29 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) : | |
| override fun addPerfMonitorListener(listener: PerfMonitorUpdateListener) { | |
| perfMonitorListeners.add(listener) | |
| - registerTracingStateListener { state, _ -> listener.onRecordingStateChanged(state) } | |
| } | |
| override fun pauseAndAnalyzeBackgroundTrace(): Boolean { | |
| - return stopAndMaybeEmitBackgroundTrace() | |
| + val emitted = stopAndMaybeEmitBackgroundTrace() | |
| + perfMonitorListeners.forEach { listener -> | |
| + listener.onRecordingStateChanged(TracingState.DISABLED) | |
| + } | |
| + | |
| + return emitted | |
| } | |
| override fun resumeBackgroundTrace() { | |
| startBackgroundTrace() | |
| + perfMonitorListeners.forEach { listener -> | |
| + listener.onRecordingStateChanged(TracingState.ENABLED_IN_BACKGROUND_MODE) | |
| + } | |
| } | |
| override fun stopBackgroundTrace() { | |
| - stopTracing() | |
| + stopAndDiscardBackgroundTrace() | |
| + perfMonitorListeners.forEach { listener -> | |
| + listener.onRecordingStateChanged(TracingState.DISABLED) | |
| + } | |
| } | |
| fun handleNativePerfIssueAdded( | |
| diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp | |
| index d8498aeea98..eeafc2085f5 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp | |
| +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp | |
| @@ -17,6 +17,35 @@ using namespace facebook::react::jsinspector_modern; | |
| namespace facebook::react { | |
| +namespace { | |
| +jni::local_ref<JTracingState::javaobject> convertCPPTracingStateToJava( | |
| + TracingState tracingState) { | |
| + auto tracingStateClass = jni::findClassLocal( | |
| + "com/facebook/react/devsupport/inspector/TracingState"); | |
| + auto valueOfMethod = | |
| + tracingStateClass->getStaticMethod<JTracingState(jstring)>("valueOf"); | |
| + | |
| + switch (tracingState) { | |
| + case TracingState::Disabled: | |
| + return valueOfMethod( | |
| + tracingStateClass, jni::make_jstring("DISABLED").get()); | |
| + | |
| + case TracingState::EnabledInBackgroundMode: | |
| + return valueOfMethod( | |
| + tracingStateClass, | |
| + jni::make_jstring("ENABLED_IN_BACKGROUND_MODE").get()); | |
| + | |
| + case TracingState::EnabledInCDPMode: | |
| + return valueOfMethod( | |
| + tracingStateClass, jni::make_jstring("ENABLED_IN_CDP_MODE").get()); | |
| + | |
| + default: | |
| + jni::throwNewJavaException( | |
| + "java/lang/IllegalStateException", "Unexpected new TracingState."); | |
| + } | |
| +} | |
| +} // namespace | |
| + | |
| JReactHostInspectorTarget::JReactHostInspectorTarget( | |
| alias_ref<JReactHostInspectorTarget::javaobject> jobj, | |
| alias_ref<JReactHostImpl> reactHostImpl, | |
| @@ -48,7 +77,7 @@ JReactHostInspectorTarget::JReactHostInspectorTarget( | |
| // Reject the connection. | |
| return nullptr; | |
| }, | |
| - {.nativePageReloads = true}); | |
| + {.nativePageReloads = true, .prefersFuseboxFrontend = true}); | |
| } | |
| } | |
| @@ -73,16 +102,13 @@ JReactHostInspectorTarget::initHybrid( | |
| } | |
| void JReactHostInspectorTarget::sendDebuggerResumeCommand() { | |
| - inspectorTarget().sendCommand(HostCommand::DebuggerResume); | |
| -} | |
| - | |
| -jsinspector_modern::HostTarget& JReactHostInspectorTarget::inspectorTarget() { | |
| if (inspectorTarget_) { | |
| - return *inspectorTarget_; | |
| + inspectorTarget_->sendCommand(HostCommand::DebuggerResume); | |
| + } else { | |
| + jni::throwNewJavaException( | |
| + "java/lang/IllegalStateException", | |
| + "Cannot send command while the Fusebox backend is not enabled"); | |
| } | |
| - jni::throwNewJavaException( | |
| - "java/lang/IllegalStateException", | |
| - "Inspector method called while the Fusebox backend is not enabled."); | |
| } | |
| jsinspector_modern::HostTargetMetadata | |
| @@ -164,22 +190,58 @@ HostTarget* JReactHostInspectorTarget::getInspectorTarget() { | |
| } | |
| bool JReactHostInspectorTarget::startBackgroundTrace() { | |
| - return inspectorTarget().startTracing( | |
| - tracing::Mode::Background, | |
| - { | |
| - tracing::Category::HiddenTimeline, | |
| - tracing::Category::RuntimeExecution, | |
| - tracing::Category::Timeline, | |
| - tracing::Category::UserTiming, | |
| - }); | |
| + if (inspectorTarget_) { | |
| + return inspectorTarget_->startTracing( | |
| + tracing::Mode::Background, | |
| + { | |
| + tracing::Category::HiddenTimeline, | |
| + tracing::Category::RuntimeExecution, | |
| + tracing::Category::Timeline, | |
| + tracing::Category::UserTiming, | |
| + }); | |
| + } else { | |
| + jni::throwNewJavaException( | |
| + "java/lang/IllegalStateException", | |
| + "Cannot start Tracing session while the Fusebox backend is not enabled."); | |
| + } | |
| } | |
| -void JReactHostInspectorTarget::stopTracing() { | |
| - inspectorTarget().stopTracing(); | |
| +tracing::HostTracingProfile JReactHostInspectorTarget::stopTracing() { | |
| + if (inspectorTarget_) { | |
| + return inspectorTarget_->stopTracing(); | |
| + } else { | |
| + jni::throwNewJavaException( | |
| + "java/lang/IllegalStateException", | |
| + "Cannot stop Tracing session while the Fusebox backend is not enabled."); | |
| + } | |
| } | |
| jboolean JReactHostInspectorTarget::stopAndMaybeEmitBackgroundTrace() { | |
| - return jboolean(inspectorTarget().stopAndMaybeEmitBackgroundTrace()); | |
| + auto capturedTrace = inspectorTarget_->stopTracing(); | |
| + if (inspectorTarget_->hasActiveSessionWithFuseboxClient()) { | |
| + inspectorTarget_->emitTracingProfileForFirstFuseboxClient( | |
| + std::move(capturedTrace)); | |
| + return jboolean(true); | |
| + } | |
| + | |
| + stashTracingProfile(std::move(capturedTrace)); | |
| + return jboolean(false); | |
| +} | |
| + | |
| +void JReactHostInspectorTarget::stopAndDiscardBackgroundTrace() { | |
| + inspectorTarget_->stopTracing(); | |
| +} | |
| + | |
| +void JReactHostInspectorTarget::stashTracingProfile( | |
| + tracing::HostTracingProfile&& hostTracingProfile) { | |
| + stashedTracingProfile_ = std::move(hostTracingProfile); | |
| +} | |
| + | |
| +std::optional<tracing::HostTracingProfile> JReactHostInspectorTarget:: | |
| + unstable_getHostTracingProfileThatWillBeEmittedOnInitialization() { | |
| + auto tracingProfile = std::move(stashedTracingProfile_); | |
| + stashedTracingProfile_.reset(); | |
| + return tracingProfile; | |
| } | |
| void JReactHostInspectorTarget::registerNatives() { | |
| @@ -194,7 +256,9 @@ void JReactHostInspectorTarget::registerNatives() { | |
| makeNativeMethod( | |
| "stopAndMaybeEmitBackgroundTrace", | |
| JReactHostInspectorTarget::stopAndMaybeEmitBackgroundTrace), | |
| - makeNativeMethod("stopTracing", JReactHostInspectorTarget::stopTracing), | |
| + makeNativeMethod( | |
| + "stopAndDiscardBackgroundTrace", | |
| + JReactHostInspectorTarget::stopAndDiscardBackgroundTrace), | |
| makeNativeMethod( | |
| "getTracingState", JReactHostInspectorTarget::getTracingState), | |
| makeNativeMethod( | |
| @@ -216,8 +280,17 @@ JReactHostInspectorTarget::getTracingState() { | |
| jlong JReactHostInspectorTarget::registerTracingStateListener( | |
| jni::alias_ref<JTracingStateListener::javaobject> listener) { | |
| auto cppListener = [globalRef = make_global(listener)]( | |
| - TracingState tracingState, bool screenshotsEnabled) { | |
| - globalRef->onStateChanged(tracingState, screenshotsEnabled); | |
| + TracingState state, bool screenshotsEnabled) { | |
| + static auto method = | |
| + globalRef->getClass() | |
| + ->getMethod<void( | |
| + jni::local_ref<JTracingState::javaobject>, jboolean)>( | |
| + "onStateChanged"); | |
| + | |
| + method( | |
| + globalRef, | |
| + convertCPPTracingStateToJava(state), | |
| + static_cast<jboolean>(screenshotsEnabled)); | |
| }; | |
| return static_cast<jlong>( | |
| @@ -235,7 +308,7 @@ HostTargetTracingDelegate* JReactHostInspectorTarget::getTracingDelegate() { | |
| void JReactHostInspectorTarget::recordFrameTimings( | |
| jni::alias_ref<JFrameTimingSequence::javaobject> frameTimingSequence) { | |
| - inspectorTarget().recordFrameTimings({ | |
| + inspectorTarget_->recordFrameTimings({ | |
| frameTimingSequence->getId(), | |
| frameTimingSequence->getThreadId(), | |
| frameTimingSequence->getBeginTimestamp(), | |
| diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h | |
| index d2389940308..6b0beae1e86 100644 | |
| --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h | |
| +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h | |
| @@ -21,53 +21,16 @@ | |
| namespace facebook::react { | |
| -struct JTracingState : public jni::JavaClass<JTracingState> { | |
| - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/inspector/TracingState;"; | |
| -}; | |
| - | |
| -namespace { | |
| - | |
| -enum class TracingState { | |
| - Disabled, | |
| - EnabledInBackgroundMode, | |
| - EnabledInCDPMode, | |
| -}; | |
| - | |
| -jni::local_ref<JTracingState::javaobject> convertCPPTracingStateToJava(TracingState tracingState) | |
| -{ | |
| - auto tracingStateClass = jni::findClassLocal("com/facebook/react/devsupport/inspector/TracingState"); | |
| - auto valueOfMethod = tracingStateClass->getStaticMethod<JTracingState(jstring)>("valueOf"); | |
| - | |
| - switch (tracingState) { | |
| - case TracingState::Disabled: | |
| - return valueOfMethod(tracingStateClass, jni::make_jstring("DISABLED").get()); | |
| - | |
| - case TracingState::EnabledInBackgroundMode: | |
| - return valueOfMethod(tracingStateClass, jni::make_jstring("ENABLED_IN_BACKGROUND_MODE").get()); | |
| - | |
| - case TracingState::EnabledInCDPMode: | |
| - return valueOfMethod(tracingStateClass, jni::make_jstring("ENABLED_IN_CDP_MODE").get()); | |
| - | |
| - default: | |
| - jni::throwNewJavaException("java/lang/IllegalStateException", "Unexpected new TracingState."); | |
| - } | |
| -} | |
| - | |
| -} // namespace | |
| - | |
| struct JTaskInterface : public jni::JavaClass<JTaskInterface> { | |
| static constexpr auto kJavaDescriptor = "Lcom/facebook/react/interfaces/TaskInterface;"; | |
| }; | |
| +struct JTracingState : public jni::JavaClass<JTracingState> { | |
| + static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/inspector/TracingState;"; | |
| +}; | |
| + | |
| struct JTracingStateListener : public jni::JavaClass<JTracingStateListener> { | |
| static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/inspector/TracingStateListener;"; | |
| - | |
| - void onStateChanged(TracingState tracingState, bool screenshotsEnabled) const | |
| - { | |
| - static auto method = | |
| - javaClassStatic()->getMethod<void(jni::local_ref<JTracingState::javaobject>, jboolean)>("onStateChanged"); | |
| - return method(self(), convertCPPTracingStateToJava(tracingState), static_cast<jboolean>(screenshotsEnabled)); | |
| - } | |
| }; | |
| struct JFrameTimingSequence : public jni::JavaClass<JFrameTimingSequence> { | |
| @@ -154,6 +117,12 @@ struct JReactHostImpl : public jni::JavaClass<JReactHostImpl> { | |
| } | |
| }; | |
| +enum class TracingState { | |
| + Disabled, | |
| + EnabledInBackgroundMode, | |
| + EnabledInCDPMode, | |
| +}; | |
| + | |
| /** | |
| * A callback that will be invoked when tracing state has changed. | |
| */ | |
| @@ -245,7 +214,7 @@ class JReactHostInspectorTarget : public jni::HybridClass<JReactHostInspectorTar | |
| /** | |
| * Stops previously started trace recording and discards the captured trace. | |
| */ | |
| - void stopTracing(); | |
| + void stopAndDiscardBackgroundTrace(); | |
| jsinspector_modern::HostTarget *getInspectorTarget(); | |
| @@ -284,6 +253,8 @@ class JReactHostInspectorTarget : public jni::HybridClass<JReactHostInspectorTar | |
| jsinspector_modern::ScopedExecutor<jsinspector_modern::NetworkRequestListener> executor) override; | |
| std::optional<std::string> captureScreenshot( | |
| const jsinspector_modern::HostTargetDelegate::PageCaptureScreenshotRequest &request) override; | |
| + std::optional<jsinspector_modern::tracing::HostTracingProfile> | |
| + unstable_getHostTracingProfileThatWillBeEmittedOnInitialization() override; | |
| jsinspector_modern::HostTargetTracingDelegate *getTracingDelegate() override; | |
| private: | |
| @@ -291,13 +262,6 @@ class JReactHostInspectorTarget : public jni::HybridClass<JReactHostInspectorTar | |
| jni::alias_ref<JReactHostInspectorTarget::javaobject> jobj, | |
| jni::alias_ref<JReactHostImpl> reactHostImpl, | |
| jni::alias_ref<JExecutor::javaobject> javaExecutor); | |
| - | |
| - /** | |
| - * Returns a reference to the HostTarget, throwing a Java IllegalStateException | |
| - * if the Fusebox backend is not enabled (i.e., inspectorTarget_ is null). | |
| - */ | |
| - jsinspector_modern::HostTarget &inspectorTarget(); | |
| - | |
| jni::global_ref<JReactHostInspectorTarget::javaobject> jobj_; | |
| // This weak reference breaks the cycle between the C++ HostTarget and the | |
| // Java ReactHostImpl, preventing memory leaks in apps that create multiple | |
| @@ -308,6 +272,20 @@ class JReactHostInspectorTarget : public jni::HybridClass<JReactHostInspectorTar | |
| std::shared_ptr<jsinspector_modern::HostTarget> inspectorTarget_; | |
| std::optional<int> inspectorPageId_; | |
| + /** | |
| + * Stops previously started trace recording and returns the captured HostTracingProfile. | |
| + */ | |
| + jsinspector_modern::tracing::HostTracingProfile stopTracing(); | |
| + /** | |
| + * Stashes previously recorded HostTracingProfile that will be emitted when | |
| + * CDP session is created. Once emitted, the value will be cleared from this | |
| + * instance. | |
| + */ | |
| + void stashTracingProfile(jsinspector_modern::tracing::HostTracingProfile &&hostTracingProfile); | |
| + /** | |
| + * Previously recorded HostTracingProfile that will be emitted when CDP session is created. | |
| + */ | |
| + std::optional<jsinspector_modern::tracing::HostTracingProfile> stashedTracingProfile_; | |
| /** | |
| * Encapsulates the logic around tracing for this HostInspectorTarget. | |
| */ | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp | |
| index d1ef2ab54f0..d535b7496d1 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp | |
| @@ -272,11 +272,13 @@ class HostAgent::Impl final { | |
| emitSystemStateChanged(isSingleHost); | |
| } | |
| - auto emitted = targetController_.maybeEmitStashedBackgroundTrace(); | |
| - assert( | |
| - emitted && | |
| - "Expected to find at least one session eligible to receive a background trace after ReactNativeApplication.enable"); | |
| - (void)emitted; | |
| + auto stashedTraceRecording = | |
| + targetController_.getDelegate() | |
| + .unstable_getHostTracingProfileThatWillBeEmittedOnInitialization(); | |
| + if (stashedTraceRecording.has_value()) { | |
| + tracingAgent_.emitExternalHostTracingProfile( | |
| + std::move(stashedTraceRecording.value())); | |
| + } | |
| return { | |
| .isFinishedHandlingRequest = true, | |
| @@ -415,8 +417,16 @@ class HostAgent::Impl final { | |
| } | |
| } | |
| - bool isEligibleForBackgroundTrace() const { | |
| - return sessionState_.isReactNativeApplicationDomainEnabled; | |
| + bool hasFuseboxClientConnected() const { | |
| + return fuseboxClientType_ == FuseboxClientType::Fusebox; | |
| + } | |
| + | |
| + void emitExternalTracingProfile( | |
| + tracing::HostTracingProfile tracingProfile) const { | |
| + assert( | |
| + hasFuseboxClientConnected() && | |
| + "Attempted to emit a trace recording to a non-Fusebox client"); | |
| + tracingAgent_.emitExternalHostTracingProfile(std::move(tracingProfile)); | |
| } | |
| void emitSystemStateChanged(bool isSingleHost) { | |
| @@ -529,9 +539,10 @@ class HostAgent::Impl final { | |
| void handleRequest(const cdp::PreparsedRequest& req) {} | |
| void setCurrentInstanceAgent(std::shared_ptr<InstanceAgent> agent) {} | |
| - bool isEligibleForBackgroundTrace() const { | |
| + bool hasFuseboxClientConnected() const { | |
| return false; | |
| } | |
| + void emitExternalTracingProfile(tracing::HostTracingProfile tracingProfile) {} | |
| void emitSystemStateChanged(bool isSingleHost) {} | |
| }; | |
| @@ -563,8 +574,17 @@ void HostAgent::setCurrentInstanceAgent( | |
| impl_->setCurrentInstanceAgent(std::move(instanceAgent)); | |
| } | |
| -bool HostAgent::isEligibleForBackgroundTrace() const { | |
| - return impl_->isEligibleForBackgroundTrace(); | |
| +bool HostAgent::hasFuseboxClientConnected() const { | |
| + return impl_->hasFuseboxClientConnected(); | |
| +} | |
| + | |
| +void HostAgent::emitExternalTracingProfile( | |
| + tracing::HostTracingProfile tracingProfile) const { | |
| + impl_->emitExternalTracingProfile(std::move(tracingProfile)); | |
| +} | |
| + | |
| +void HostAgent::emitSystemStateChanged(bool isSingleHost) const { | |
| + impl_->emitSystemStateChanged(isSingleHost); | |
| } | |
| #pragma mark - Tracing | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h | |
| index 083632667f1..8789cb5d32c 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h | |
| @@ -67,16 +67,23 @@ class HostAgent final { | |
| void setCurrentInstanceAgent(std::shared_ptr<InstanceAgent> agent); | |
| /** | |
| - * Returns whether this HostAgent is eligible to receive notifications about | |
| - * background traces. | |
| + * Returns whether this HostAgent is part of the session that has an active | |
| + * Fusebox client connecte, i.e. with Chrome DevTools Frontend fork for React | |
| + * Native. | |
| */ | |
| - bool isEligibleForBackgroundTrace() const; | |
| + bool hasFuseboxClientConnected() const; | |
| + | |
| + /** | |
| + * Emits the HostTracingProfile that was captured externally, not via the | |
| + * CDP-initiated request. | |
| + */ | |
| + void emitExternalTracingProfile(tracing::HostTracingProfile tracingProfile) const; | |
| /** | |
| * Emits a system state changed event when the number of ReactHost instances | |
| * changes. | |
| */ | |
| - void emitSystemStateChanged(bool isSingleHost); | |
| + void emitSystemStateChanged(bool isSingleHost) const; | |
| private: | |
| // We use the private implementation idiom to ensure this class has the same | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.cpp b/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.cpp | |
| index 637198d2a57..26c7e1ca849 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.cpp | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.cpp | |
| @@ -8,7 +8,6 @@ | |
| #include "HostTarget.h" | |
| #include "HostAgent.h" | |
| #include "HostTargetTraceRecording.h" | |
| -#include "HostTargetTracing.h" | |
| #include "InspectorInterfaces.h" | |
| #include "InspectorUtilities.h" | |
| #include "InstanceTarget.h" | |
| @@ -103,12 +102,18 @@ class HostTargetSession { | |
| } | |
| } | |
| - HostAgent& agent() { | |
| - return hostAgent_; | |
| + /** | |
| + * Returns whether the ReactNativeApplication CDP domain is enabled. | |
| + * | |
| + * Chrome DevTools Frontend enables this domain as a client. | |
| + */ | |
| + bool hasFuseboxClient() const { | |
| + return hostAgent_.hasFuseboxClientConnected(); | |
| } | |
| - FrontendChannel dangerouslyGetFrontendChannel() { | |
| - return frontendChannel_; | |
| + void emitHostTracingProfile( | |
| + tracing::HostTracingProfile tracingProfile) const { | |
| + hostAgent_.emitExternalTracingProfile(std::move(tracingProfile)); | |
| } | |
| private: | |
| @@ -319,10 +324,6 @@ bool HostTargetController::decrementPauseOverlayCounter() { | |
| return --pauseOverlayCounter_ != 0; | |
| } | |
| -bool HostTargetController::maybeEmitStashedBackgroundTrace() { | |
| - return target_.maybeEmitStashedBackgroundTrace(); | |
| -} | |
| - | |
| namespace { | |
| struct StaticHostTargetMetadata { | |
| @@ -380,33 +381,32 @@ folly::dynamic createHostMetadataPayload(const HostTargetMetadata& metadata) { | |
| return result; | |
| } | |
| -bool HostTarget::maybeEmitStashedBackgroundTrace() { | |
| - std::vector<FrontendChannel> eligibleFrontendChannels; | |
| - eligibleFrontendChannels.reserve(sessions_.size()); | |
| - sessions_.forEach([&eligibleFrontendChannels](auto& session) { | |
| - if (session.agent().isEligibleForBackgroundTrace()) { | |
| - eligibleFrontendChannels.push_back( | |
| - session.dangerouslyGetFrontendChannel()); | |
| - } | |
| +bool HostTarget::hasActiveSessionWithFuseboxClient() const { | |
| + bool hasActiveFuseboxSession = false; | |
| + sessions_.forEach([&](HostTargetSession& session) { | |
| + hasActiveFuseboxSession |= session.hasFuseboxClient(); | |
| }); | |
| - | |
| - if (eligibleFrontendChannels.empty()) { | |
| - return false; | |
| - } | |
| - | |
| - auto stashedTrace = std::exchange(stashedTracingProfile_, std::nullopt); | |
| - if (stashedTrace) { | |
| - emitNotificationsForTracingProfile( | |
| - std::move(*stashedTrace), | |
| - eligibleFrontendChannels, | |
| - /* isBackgroundTrace */ true); | |
| - } | |
| - return true; | |
| + return hasActiveFuseboxSession; | |
| } | |
| -bool HostTarget::stopAndMaybeEmitBackgroundTrace() { | |
| - stashedTracingProfile_ = stopTracing(); | |
| - return maybeEmitStashedBackgroundTrace(); | |
| +void HostTarget::emitTracingProfileForFirstFuseboxClient( | |
| + tracing::HostTracingProfile tracingProfile) const { | |
| + bool emitted = false; | |
| + sessions_.forEach([&](HostTargetSession& session) { | |
| + if (emitted) { | |
| + /** | |
| + * HostTracingProfile object is not copiable for performance reasons, | |
| + * because it could contain large Runtime sampling profile object. | |
| + * | |
| + * This approach would not work with multi-client debugger setup. | |
| + */ | |
| + return; | |
| + } | |
| + if (session.hasFuseboxClient()) { | |
| + session.emitHostTracingProfile(std::move(tracingProfile)); | |
| + emitted = true; | |
| + } | |
| + }); | |
| } | |
| } // namespace facebook::react::jsinspector_modern | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h b/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h | |
| index 1030b90879f..798fc6d8dc0 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h | |
| @@ -206,6 +206,19 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate { | |
| return std::nullopt; | |
| } | |
| + /** | |
| + * [Experimental] Will be called at the CDP session initialization to get the | |
| + * trace recording that may have been stashed by the Host from the previous | |
| + * background session. | |
| + * | |
| + * \return the HostTracingProfile if there is one that needs to be | |
| + * displayed, otherwise std::nullopt. | |
| + */ | |
| + virtual std::optional<tracing::HostTracingProfile> unstable_getHostTracingProfileThatWillBeEmittedOnInitialization() | |
| + { | |
| + return std::nullopt; | |
| + } | |
| + | |
| /** | |
| * An optional delegate that will be used by HostTarget to notify about tracing-related events. | |
| */ | |
| @@ -268,12 +281,6 @@ class HostTargetController final { | |
| */ | |
| tracing::HostTracingProfile stopTracing(); | |
| - /** | |
| - * If there is a stashed background trace, emit it to all eligible sessions. | |
| - * \return true if an eligible session is found (even if there was no stashed background trace). | |
| - */ | |
| - bool maybeEmitStashedBackgroundTrace(); | |
| - | |
| private: | |
| HostTarget &target_; | |
| size_t pauseOverlayCounter_{0}; | |
| @@ -370,13 +377,23 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget> | |
| tracing::HostTracingProfile stopTracing(); | |
| /** | |
| - * Stops previously started trace recording and: | |
| - * - If there is an active CDP session with ReactNativeApplication domain | |
| - * enabled, emits the trace and returns true. | |
| - * - Otherwise, stashes the captured trace, that will be emitted when a CDP | |
| - * session enables ReactNativeApplication. Returns false. | |
| + * Returns whether there is an active session with the Fusebox client, i.e. | |
| + * with Chrome DevTools Frontend fork for React Native. | |
| */ | |
| - bool stopAndMaybeEmitBackgroundTrace(); | |
| + bool hasActiveSessionWithFuseboxClient() const; | |
| + | |
| + /** | |
| + * Emits the HostTracingProfile for the first active session with the Fusebox | |
| + * client. | |
| + * | |
| + * @see \c hasActiveFrontendSession | |
| + */ | |
| + void emitTracingProfileForFirstFuseboxClient(tracing::HostTracingProfile tracingProfile) const; | |
| + | |
| + /** | |
| + * Emits a system state changed event to all active sessions. | |
| + */ | |
| + void emitSystemStateChanged(bool isSingleHost) const; | |
| /** | |
| * An endpoint for the Host to report frame timings that will be recorded if and only if there is currently an active | |
| @@ -416,11 +433,6 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget> | |
| * Should only be allocated when there is an active tracing session. | |
| */ | |
| std::unique_ptr<HostTargetTraceRecording> traceRecording_{nullptr}; | |
| - /** | |
| - * Previously recorded HostTracingProfile that will be emitted when CDP session is created | |
| - * and enables ReactNativeApplication. Once emitted, the value will be cleared. | |
| - */ | |
| - std::optional<tracing::HostTracingProfile> stashedTracingProfile_; | |
| /** | |
| * Protects the state inside traceRecording_. | |
| * | |
| @@ -447,12 +459,6 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget> | |
| */ | |
| void installPerfIssuesBinding(); | |
| - /** | |
| - * If there is a stashed background trace, emit it to the first eligible session. | |
| - * \return true if an eligible session is found (even if there was no stashed background trace). | |
| - */ | |
| - bool maybeEmitStashedBackgroundTrace(); | |
| - | |
| // Necessary to allow HostAgent to access HostTarget's internals in a | |
| // controlled way (i.e. only HostTargetController gets friend access, while | |
| // HostAgent itself doesn't). | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp | |
| index 6a08e59e39e..ab5a973f12c 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp | |
| @@ -29,7 +29,8 @@ folly::dynamic targetCapabilitiesToDynamic( | |
| const InspectorTargetCapabilities& capabilities) { | |
| return folly::dynamic::object( | |
| "nativePageReloads", capabilities.nativePageReloads)( | |
| - "nativeSourceCodeFetching", capabilities.nativeSourceCodeFetching); | |
| + "nativeSourceCodeFetching", capabilities.nativeSourceCodeFetching)( | |
| + "prefersFuseboxFrontend", capabilities.prefersFuseboxFrontend); | |
| } | |
| namespace { | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp | |
| index ba7447baa23..53dcc0a3469 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp | |
| @@ -259,13 +259,6 @@ class Stream : public NetworkRequestListener, | |
| }; | |
| } // namespace | |
| -NetworkIOAgent::~NetworkIOAgent() { | |
| - if (networkAgentId_) { | |
| - NetworkHandler::getInstance().disableAgent(*networkAgentId_); | |
| - networkAgentId_ = std::nullopt; | |
| - } | |
| -} | |
| - | |
| bool NetworkIOAgent::handleRequest( | |
| const cdp::PreparsedRequest& req, | |
| LoadNetworkResourceDelegate& delegate) { | |
| @@ -285,17 +278,15 @@ bool NetworkIOAgent::handleRequest( | |
| // @cdp Network.enable support is experimental. | |
| if (req.method == "Network.enable") { | |
| - networkAgentId_ = networkHandler.enableAgent(frontendChannel_); | |
| + networkHandler.setFrontendChannel(frontendChannel_); | |
| + networkHandler.enable(); | |
| // NOTE: Domain enable/disable responses are sent by HostAgent. | |
| return false; | |
| } | |
| // @cdp Network.disable support is experimental. | |
| if (req.method == "Network.disable") { | |
| - if (networkAgentId_) { | |
| - networkHandler.disableAgent(*networkAgentId_); | |
| - networkAgentId_ = std::nullopt; | |
| - } | |
| + networkHandler.disable(); | |
| // NOTE: Domain enable/disable responses are sent by HostAgent. | |
| return false; | |
| } | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp | |
| index d20203d0e88..2c8b2030a7a 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp | |
| @@ -6,8 +6,8 @@ | |
| */ | |
| #include "TracingAgent.h" | |
| -#include "HostTargetTracing.h" | |
| +#include <jsinspector-modern/tracing/HostTracingProfileSerializer.h> | |
| #include <jsinspector-modern/tracing/PerformanceTracer.h> | |
| #include <jsinspector-modern/tracing/RuntimeSamplingProfileTraceEventSerializer.h> | |
| #include <jsinspector-modern/tracing/TraceEventSerializer.h> | |
| @@ -15,6 +15,26 @@ | |
| namespace facebook::react::jsinspector_modern { | |
| +namespace { | |
| + | |
| +/** | |
| + * Threshold for the size Trace Event chunk, that will be flushed out with | |
| + * Tracing.dataCollected event. | |
| + */ | |
| +const uint16_t TRACE_EVENT_CHUNK_SIZE = 1000; | |
| + | |
| +/** | |
| + * The maximum number of ProfileChunk trace events | |
| + * that will be sent in a single CDP Tracing.dataCollected message. | |
| + * TODO(T219394401): Increase the size once we manage the queue on OkHTTP | |
| + side | |
| + * properly and avoid WebSocket disconnections when sending a message larger | |
| + * than 16MB. | |
| + */ | |
| +const uint16_t PROFILE_TRACE_EVENT_CHUNK_SIZE = 1; | |
| + | |
| +} // namespace | |
| + | |
| TracingAgent::TracingAgent( | |
| FrontendChannel frontendChannel, | |
| SessionState& sessionState, | |
| @@ -74,8 +94,6 @@ bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) { | |
| bool didNotHaveAlreadyRunningRecording = hostTargetController_.startTracing( | |
| tracing::Mode::CDP, std::move(enabledCategories)); | |
| if (!didNotHaveAlreadyRunningRecording) { | |
| - // @cdp Tracing.start fails if there is a tracing session already running | |
| - // in the current target. This matches Chrome's behavior. | |
| frontendChannel_( | |
| cdp::jsonError( | |
| req.id, | |
| @@ -96,14 +114,38 @@ bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) { | |
| // Send response to Tracing.end request. | |
| frontendChannel_(cdp::jsonResult(req.id)); | |
| - emitNotificationsForTracingProfile( | |
| - std::move(tracingProfile), | |
| - frontendChannel_, | |
| - /* isBackgroundTrace */ false); | |
| + emitHostTracingProfile(std::move(tracingProfile)); | |
| return true; | |
| } | |
| return false; | |
| } | |
| +void TracingAgent::emitExternalHostTracingProfile( | |
| + tracing::HostTracingProfile tracingProfile) const { | |
| + frontendChannel_( | |
| + cdp::jsonNotification("ReactNativeApplication.traceRequested")); | |
| + emitHostTracingProfile(std::move(tracingProfile)); | |
| +} | |
| + | |
| +void TracingAgent::emitHostTracingProfile( | |
| + tracing::HostTracingProfile tracingProfile) const { | |
| + auto dataCollectedCallback = [this](folly::dynamic&& eventsChunk) { | |
| + frontendChannel_( | |
| + cdp::jsonNotification( | |
| + "Tracing.dataCollected", | |
| + folly::dynamic::object("value", std::move(eventsChunk)))); | |
| + }; | |
| + tracing::HostTracingProfileSerializer::emitAsDataCollectedChunks( | |
| + std::move(tracingProfile), | |
| + dataCollectedCallback, | |
| + TRACE_EVENT_CHUNK_SIZE, | |
| + PROFILE_TRACE_EVENT_CHUNK_SIZE); | |
| + | |
| + frontendChannel_( | |
| + cdp::jsonNotification( | |
| + "Tracing.tracingComplete", | |
| + folly::dynamic::object("dataLossOccurred", false))); | |
| +} | |
| + | |
| } // namespace facebook::react::jsinspector_modern | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.h b/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.h | |
| index 2fe4c8ad666..d0f474f1234 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.h | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.h | |
| @@ -41,6 +41,11 @@ class TracingAgent { | |
| */ | |
| bool handleRequest(const cdp::PreparsedRequest &req); | |
| + /** | |
| + * Emits the HostTracingProfile that was stashed externally by the HostTarget. | |
| + */ | |
| + void emitExternalHostTracingProfile(tracing::HostTracingProfile tracingProfile) const; | |
| + | |
| private: | |
| /** | |
| * A channel used to send responses and events to the frontend. | |
| @@ -50,6 +55,12 @@ class TracingAgent { | |
| SessionState &sessionState_; | |
| HostTargetController &hostTargetController_; | |
| + | |
| + /** | |
| + * Emits captured HostTracingProfile in a series of | |
| + * Tracing.dataCollected events, followed by a Tracing.tracingComplete event. | |
| + */ | |
| + void emitHostTracingProfile(tracing::HostTracingProfile tracingProfile) const; | |
| }; | |
| } // namespace facebook::react::jsinspector_modern | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp | |
| index 14ddcafac2a..5769ef2f60c 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp | |
| @@ -189,8 +189,7 @@ void PerformanceTracer::reportMeasure( | |
| const std::string& name, | |
| HighResTimeStamp start, | |
| HighResDuration duration, | |
| - folly::dynamic&& detail, | |
| - std::optional<folly::dynamic> stackTrace) { | |
| + folly::dynamic&& detail) { | |
| if (!tracingAtomic_) { | |
| return; | |
| } | |
| @@ -207,7 +206,6 @@ void PerformanceTracer::reportMeasure( | |
| .duration = duration, | |
| .detail = std::move(detail), | |
| .threadId = getCurrentThreadId(), | |
| - .stackTrace = std::move(stackTrace), | |
| }); | |
| } | |
| @@ -218,8 +216,7 @@ void PerformanceTracer::reportTimeStamp( | |
| std::optional<std::string> trackName, | |
| std::optional<std::string> trackGroup, | |
| std::optional<ConsoleTimeStampColor> color, | |
| - std::optional<folly::dynamic> detail, | |
| - std::optional<folly::dynamic> stackTrace) { | |
| + std::optional<folly::dynamic> detail) { | |
| if (!tracingAtomic_) { | |
| return; | |
| } | |
| @@ -238,7 +235,6 @@ void PerformanceTracer::reportTimeStamp( | |
| .trackGroup = std::move(trackGroup), | |
| .color = std::move(color), | |
| .detail = std::move(detail), | |
| - .stackTrace = std::move(stackTrace), | |
| .threadId = getCurrentThreadId(), | |
| }); | |
| } | |
| @@ -312,27 +308,6 @@ void PerformanceTracer::reportResourceSendRequest( | |
| }); | |
| } | |
| -void PerformanceTracer::reportResourceReceivedData( | |
| - const std::string& devtoolsRequestId, | |
| - HighResTimeStamp start, | |
| - int encodedDataLength) { | |
| - if (!tracingAtomic_) { | |
| - return; | |
| - }; | |
| - | |
| - std::lock_guard<std::mutex> lock(mutex_); | |
| - if (!tracingAtomic_) { | |
| - return; | |
| - } | |
| - | |
| - enqueueEvent( | |
| - PerformanceTracerResourceReceivedData{ | |
| - .requestId = devtoolsRequestId, | |
| - .start = start, | |
| - .encodedDataLength = encodedDataLength, | |
| - .threadId = getCurrentThreadId()}); | |
| -} | |
| - | |
| void PerformanceTracer::reportResourceReceiveResponse( | |
| const std::string& devtoolsRequestId, | |
| HighResTimeStamp start, | |
| @@ -598,10 +573,6 @@ void PerformanceTracer::enqueueTraceEventsFromPerformanceTracerEvent( | |
| beginEventArgs = | |
| folly::dynamic::object("detail", folly::toJson(event.detail)); | |
| } | |
| - if (event.stackTrace) { | |
| - beginEventArgs["data"] = folly::dynamic::object( | |
| - "rnStackTrace", std::move(*event.stackTrace)); | |
| - } | |
| auto eventId = ++performanceMeasureCount_; | |
| @@ -691,9 +662,6 @@ void PerformanceTracer::enqueueTraceEventsFromPerformanceTracerEvent( | |
| } | |
| data["devtools"] = folly::toJson(devtoolsDetail); | |
| } | |
| - if (event.stackTrace) { | |
| - data["rnStackTrace"] = std::move(*event.stackTrace); | |
| - } | |
| events.emplace_back( | |
| TraceEvent{ | |
| @@ -727,23 +695,6 @@ void PerformanceTracer::enqueueTraceEventsFromPerformanceTracerEvent( | |
| .args = folly::dynamic::object("data", std::move(data)), | |
| }); | |
| }, | |
| - [&](PerformanceTracerResourceReceivedData&& event) { | |
| - folly::dynamic data = folly::dynamic::object( | |
| - "encodedDataLength", event.encodedDataLength)( | |
| - "requestId", std::move(event.requestId)); | |
| - | |
| - events.emplace_back( | |
| - TraceEvent{ | |
| - .name = "ResourceReceivedData", | |
| - .cat = {Category::Timeline}, | |
| - .ph = 'I', | |
| - .ts = event.start, | |
| - .pid = processId_, | |
| - .s = 't', | |
| - .tid = event.threadId, | |
| - .args = folly::dynamic::object("data", std::move(data)), | |
| - }); | |
| - }, | |
| [&](PerformanceTracerResourceReceiveResponse&& event) { | |
| folly::dynamic headersEntries = folly::dynamic::array; | |
| for (const auto& [key, value] : event.headers) { | |
| diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tracing/TracingCategory.h b/packages/react-native/ReactCommon/jsinspector-modern/tracing/TracingCategory.h | |
| index 24c1880b9df..011c05fd1c0 100644 | |
| --- a/packages/react-native/ReactCommon/jsinspector-modern/tracing/TracingCategory.h | |
| +++ b/packages/react-native/ReactCommon/jsinspector-modern/tracing/TracingCategory.h | |
| @@ -42,8 +42,6 @@ inline std::string tracingCategoryToString(const Category &category) | |
| return "disabled-by-default-devtools.timeline.frame"; | |
| case Category::Screenshot: | |
| return "disabled-by-default-devtools.screenshot"; | |
| - default: | |
| - folly::assume_unreachable(); | |
| } | |
| } | |
| diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm | |
| index 5ff41abd148..207e602260b 100644 | |
| --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm | |
| +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm | |
| @@ -267,6 +267,10 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho | |
| launchOptions:launchOptions]; | |
| } | |
| +/** | |
| + Host initialization should not be resource intensive. A host may be created before any intention of using React Native | |
| + has been expressed. | |
| + */ | |
| - (instancetype)initWithBundleURLProvider:(RCTHostBundleURLProvider)provider | |
| hostDelegate:(id<RCTHostDelegate>)hostDelegate | |
| turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate | |
| @@ -278,32 +282,24 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho | |
| turboModuleManagerDelegate:turboModuleManagerDelegate | |
| jsEngineProvider:jsEngineProvider | |
| launchOptions:launchOptions | |
| - bundleConfiguration:[RCTBundleConfiguration defaultConfiguration] | |
| devMenuConfiguration:[RCTDevMenuConfiguration defaultConfiguration]]; | |
| } | |
| -/** | |
| - Host initialization should not be resource intensive. A host may be created before any intention of using React Native | |
| - has been expressed. | |
| - */ | |
| - (instancetype)initWithBundleURLProvider:(RCTHostBundleURLProvider)provider | |
| hostDelegate:(id<RCTHostDelegate>)hostDelegate | |
| turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate | |
| jsEngineProvider:(RCTHostJSEngineProvider)jsEngineProvider | |
| launchOptions:(nullable NSDictionary *)launchOptions | |
| - bundleConfiguration:(RCTBundleConfiguration *)bundleConfiguration | |
| devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration | |
| { | |
| if (self = [super init]) { | |
| _hostDelegate = hostDelegate; | |
| _turboModuleManagerDelegate = turboModuleManagerDelegate; | |
| - _bundleManager = [[RCTBundleManager alloc] initWithBundleConfig:bundleConfiguration]; | |
| + _bundleManager = [RCTBundleManager new]; | |
| _moduleRegistry = [RCTModuleRegistry new]; | |
| _jsEngineProvider = [jsEngineProvider copy]; | |
| _launchOptions = [launchOptions copy]; | |
| - [self setBundleURLProvider:provider]; | |
| - | |
| __weak RCTHost *weakSelf = self; | |
| auto bundleURLGetter = ^NSURL *() { | |
| RCTHost *strongSelf = weakSelf; | |
| @@ -370,7 +366,7 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho | |
| } | |
| return strongSelf->_inspectorTarget->connect(std::move(remote)); | |
| }, | |
| - {.nativePageReloads = true}); | |
| + {.nativePageReloads = true, .prefersFuseboxFrontend = true}); | |
| } | |
| if (_instance) { | |
| RCTLogWarn( | |
| @@ -486,14 +482,7 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho | |
| - (void)instance:(RCTInstance *)instance didInitializeRuntime:(facebook::jsi::Runtime &)runtime | |
| { | |
| - if ([_hostDelegate respondsToSelector:@selector(host:didInitializeRuntime:)]) { | |
| - [_hostDelegate host:self didInitializeRuntime:runtime]; | |
| - } | |
| - // Runtime delegate is deprecated as of 0.84 | |
| -#pragma clang diagnostic push | |
| -#pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
| [self.runtimeDelegate host:self didInitializeRuntime:runtime]; | |
| -#pragma clang diagnostic pop | |
| } | |
| - (void)loadBundleAtURL:(NSURL *)sourceURL | |
| @@ -576,7 +565,7 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho | |
| // Sanitize the bundle URL | |
| _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString]; | |
| - // Update the global bundle URL | |
| + // Update the global bundle URLq | |
| RCTReloadCommandSetBundleURL(_bundleURL); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment