react-native 0.83.4 → 0.83.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Utilities/Appearance.js +6 -1
- package/Libraries/Utilities/HMRClient.js +28 -1
- package/React/Base/RCTVersion.m +1 -1
- package/React/CoreModules/RCTDevLoadingView.mm +17 -0
- package/React/DevSupport/RCTFrameTimingsObserver.h +24 -0
- package/React/DevSupport/RCTFrameTimingsObserver.mm +298 -0
- package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +16 -0
- package/ReactAndroid/api/ReactAndroid.api +0 -9
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt +7 -7
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt +4 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt +16 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +275 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingState.kt +17 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingStateListener.kt +15 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/{interfaces → inspector}/TracingStateProvider.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorInspectorTargetBinding.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt +4 -4
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt +3 -3
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorUpdateListener.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +13 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +21 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +23 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt +39 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt +20 -19
- package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.kt +6 -12
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +86 -4
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt +3 -3
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt +10 -6
- package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.cpp +22 -0
- package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.h +2 -0
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +29 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +7 -1
- package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp +196 -17
- package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h +168 -18
- package/ReactAndroid/src/main/jni/third-party/folly/CMakeLists.txt +1 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp +44 -2
- package/ReactCommon/jsinspector-modern/HostAgent.cpp +45 -10
- package/ReactCommon/jsinspector-modern/HostAgent.h +2 -2
- package/ReactCommon/jsinspector-modern/HostTarget.cpp +14 -7
- package/ReactCommon/jsinspector-modern/HostTarget.h +101 -14
- package/ReactCommon/jsinspector-modern/HostTargetTraceRecording.cpp +39 -8
- package/ReactCommon/jsinspector-modern/HostTargetTraceRecording.h +42 -5
- package/ReactCommon/jsinspector-modern/HostTargetTracing.cpp +54 -21
- package/ReactCommon/jsinspector-modern/HostTargetTracing.h +89 -0
- package/ReactCommon/jsinspector-modern/InspectorFlags.cpp +12 -0
- package/ReactCommon/jsinspector-modern/InspectorFlags.h +12 -0
- package/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp +3 -7
- package/ReactCommon/jsinspector-modern/InstanceAgent.cpp +2 -11
- package/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +1 -1
- package/ReactCommon/jsinspector-modern/RuntimeAgent.cpp +19 -0
- package/ReactCommon/jsinspector-modern/RuntimeAgent.h +7 -0
- package/ReactCommon/jsinspector-modern/RuntimeTarget.cpp +33 -0
- package/ReactCommon/jsinspector-modern/RuntimeTarget.h +6 -0
- package/ReactCommon/jsinspector-modern/TracingAgent.cpp +29 -13
- package/ReactCommon/jsinspector-modern/TracingAgent.h +5 -4
- package/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +65 -0
- package/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +23 -2
- package/ReactCommon/jsinspector-modern/tests/JsiIntegrationTest.cpp +1 -0
- package/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp +1 -0
- package/ReactCommon/jsinspector-modern/tests/TracingTest.cpp +335 -0
- package/ReactCommon/jsinspector-modern/tests/TracingTest.h +95 -0
- package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.cpp +10 -0
- package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.h +3 -1
- package/ReactCommon/jsinspector-modern/tracing/CMakeLists.txt +1 -0
- package/ReactCommon/jsinspector-modern/tracing/FrameTimingSequence.h +61 -0
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfile.h +43 -0
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.cpp +165 -0
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.h +50 -0
- package/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp +16 -14
- package/ReactCommon/jsinspector-modern/tracing/PerformanceTracerSection.h +113 -0
- package/ReactCommon/jsinspector-modern/tracing/React-jsinspectortracing.podspec +1 -0
- package/ReactCommon/jsinspector-modern/tracing/TimeWindowedBuffer.h +158 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEvent.h +2 -1
- package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +100 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.h +60 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.cpp +44 -1
- package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.h +7 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceRecordingState.h +18 -7
- package/ReactCommon/jsinspector-modern/tracing/TracingCategory.h +136 -0
- package/ReactCommon/jsinspector-modern/tracing/tests/TimeWindowedBufferTest.cpp +352 -0
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +9 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +11 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +65 -29
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +6 -2
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +9 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +19 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +3 -1
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +3 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +11 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +5 -1
- package/ReactCommon/react/performance/timeline/PerformanceObserver.cpp +18 -6
- package/ReactCommon/react/performance/timeline/PerformanceObserver.h +2 -0
- package/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +115 -0
- package/ReactCommon/{jsinspector-modern → react/utils}/Base64.h +2 -2
- package/gradle/libs.versions.toml +1 -1
- package/package.json +10 -10
- package/scripts/cocoapods/utils.rb +1 -0
- package/src/private/featureflags/ReactNativeFeatureFlags.js +11 -1
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +3 -1
- package/third-party-podspecs/RCT-Folly.podspec +1 -1
- package/third-party-podspecs/fmt.podspec +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/TracingState.kt +0 -19
- package/ReactCommon/jsinspector-modern/tracing/TraceRecordingStateSerializer.cpp +0 -68
- package/ReactCommon/jsinspector-modern/tracing/TraceRecordingStateSerializer.h +0 -42
- package/ReactCommon/jsinspector-modern/tracing/TracingState.h +0 -24
|
@@ -99,7 +99,12 @@ export function setColorScheme(colorScheme: ColorSchemeName): void {
|
|
|
99
99
|
if (NativeAppearance != null) {
|
|
100
100
|
NativeAppearance.setColorScheme(colorScheme);
|
|
101
101
|
state.appearance = {
|
|
102
|
-
|
|
102
|
+
// When setting to 'unspecified', get the actual system color scheme.
|
|
103
|
+
// Fall back to the passed value if getColorScheme() returns null.
|
|
104
|
+
colorScheme:
|
|
105
|
+
colorScheme === 'unspecified'
|
|
106
|
+
? (NativeAppearance.getColorScheme() ?? colorScheme)
|
|
107
|
+
: colorScheme,
|
|
103
108
|
};
|
|
104
109
|
}
|
|
105
110
|
}
|
|
@@ -26,6 +26,7 @@ let hmrUnavailableReason: string | null = null;
|
|
|
26
26
|
let hmrOrigin: string | null = null;
|
|
27
27
|
let currentCompileErrorMessage: string | null = null;
|
|
28
28
|
let didConnect: boolean = false;
|
|
29
|
+
let lastMarkerChangeId: ?string = null;
|
|
29
30
|
let pendingLogs: Array<[LogLevel, $ReadOnlyArray<mixed>]> = [];
|
|
30
31
|
|
|
31
32
|
type LogLevel =
|
|
@@ -229,10 +230,15 @@ Error: ${e.message}`;
|
|
|
229
230
|
}
|
|
230
231
|
});
|
|
231
232
|
|
|
232
|
-
client.on('update-done',
|
|
233
|
+
client.on('update-done', body => {
|
|
233
234
|
pendingUpdatesCount--;
|
|
234
235
|
if (pendingUpdatesCount === 0) {
|
|
235
236
|
DevLoadingView.hide();
|
|
237
|
+
const changeId = body?.changeId;
|
|
238
|
+
if (changeId != null && changeId !== lastMarkerChangeId) {
|
|
239
|
+
lastMarkerChangeId = changeId;
|
|
240
|
+
emitFastRefreshCompleteEvents();
|
|
241
|
+
}
|
|
236
242
|
}
|
|
237
243
|
});
|
|
238
244
|
|
|
@@ -378,4 +384,25 @@ function showCompileError() {
|
|
|
378
384
|
throw error;
|
|
379
385
|
}
|
|
380
386
|
|
|
387
|
+
function emitFastRefreshCompleteEvents() {
|
|
388
|
+
// Add marker entry in performance timeline
|
|
389
|
+
performance.mark('Fast Refresh - Update done', {
|
|
390
|
+
detail: {
|
|
391
|
+
devtools: {
|
|
392
|
+
dataType: 'marker',
|
|
393
|
+
color: 'primary',
|
|
394
|
+
tooltipText: 'Fast Refresh \u269b',
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Notify CDP clients via internal binding
|
|
400
|
+
if (
|
|
401
|
+
// $FlowFixMe[prop-missing] - Injected by RuntimeTarget
|
|
402
|
+
typeof globalThis.__notifyFastRefreshComplete === 'function'
|
|
403
|
+
) {
|
|
404
|
+
globalThis.__notifyFastRefreshComplete();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
381
408
|
export default HMRClient;
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -50,10 +50,27 @@ RCT_EXPORT_MODULE()
|
|
|
50
50
|
selector:@selector(hide)
|
|
51
51
|
name:RCTJavaScriptDidFailToLoadNotification
|
|
52
52
|
object:nil];
|
|
53
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
54
|
+
selector:@selector(hide)
|
|
55
|
+
name:@"RCTInstanceDidLoadBundle"
|
|
56
|
+
object:nil];
|
|
53
57
|
}
|
|
54
58
|
return self;
|
|
55
59
|
}
|
|
56
60
|
|
|
61
|
+
- (void)dealloc
|
|
62
|
+
{
|
|
63
|
+
[self clearInitialMessageDelay];
|
|
64
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
65
|
+
UIWindow *window = _window;
|
|
66
|
+
_window = nil;
|
|
67
|
+
if (window) {
|
|
68
|
+
RCTExecuteOnMainQueue(^{
|
|
69
|
+
window.hidden = YES;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
+ (void)setEnabled:(BOOL)enabled
|
|
58
75
|
{
|
|
59
76
|
RCTDevLoadingViewSetEnabled(enabled);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import <Foundation/Foundation.h>
|
|
9
|
+
|
|
10
|
+
#ifdef __cplusplus
|
|
11
|
+
#import <jsinspector-modern/tracing/FrameTimingSequence.h>
|
|
12
|
+
|
|
13
|
+
using RCTFrameTimingCallback = void (^)(facebook::react::jsinspector_modern::tracing::FrameTimingSequence);
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
@interface RCTFrameTimingsObserver : NSObject
|
|
17
|
+
|
|
18
|
+
#ifdef __cplusplus
|
|
19
|
+
- (instancetype)initWithScreenshotsEnabled:(BOOL)screenshotsEnabled callback:(RCTFrameTimingCallback)callback;
|
|
20
|
+
#endif
|
|
21
|
+
- (void)start;
|
|
22
|
+
- (void)stop;
|
|
23
|
+
|
|
24
|
+
@end
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import "RCTFrameTimingsObserver.h"
|
|
9
|
+
|
|
10
|
+
#import <UIKit/UIKit.h>
|
|
11
|
+
|
|
12
|
+
#import <mach/thread_act.h>
|
|
13
|
+
#import <pthread.h>
|
|
14
|
+
|
|
15
|
+
#import <atomic>
|
|
16
|
+
#import <chrono>
|
|
17
|
+
#import <mutex>
|
|
18
|
+
#import <optional>
|
|
19
|
+
#import <vector>
|
|
20
|
+
|
|
21
|
+
#import <react/timing/primitives.h>
|
|
22
|
+
|
|
23
|
+
using namespace facebook::react;
|
|
24
|
+
|
|
25
|
+
static constexpr CGFloat kScreenshotScaleFactor = 1.0;
|
|
26
|
+
static constexpr CGFloat kScreenshotJPEGQuality = 0.8;
|
|
27
|
+
|
|
28
|
+
namespace {
|
|
29
|
+
|
|
30
|
+
// Stores a captured frame screenshot and its associated metadata, used for
|
|
31
|
+
// buffering frames during dynamic sampling.
|
|
32
|
+
struct FrameData {
|
|
33
|
+
UIImage *image;
|
|
34
|
+
uint64_t frameId;
|
|
35
|
+
jsinspector_modern::tracing::ThreadId threadId;
|
|
36
|
+
HighResTimeStamp beginTimestamp;
|
|
37
|
+
HighResTimeStamp endTimestamp;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
} // namespace
|
|
41
|
+
|
|
42
|
+
@implementation RCTFrameTimingsObserver {
|
|
43
|
+
BOOL _screenshotsEnabled;
|
|
44
|
+
RCTFrameTimingCallback _callback;
|
|
45
|
+
CADisplayLink *_displayLink;
|
|
46
|
+
uint64_t _frameCounter;
|
|
47
|
+
// Serial queue for encoding work (single background thread). We limit to 1
|
|
48
|
+
// thread to minimize the performance impact of screenshot recording.
|
|
49
|
+
dispatch_queue_t _encodingQueue;
|
|
50
|
+
std::atomic<bool> _running;
|
|
51
|
+
uint64_t _lastScreenshotHash;
|
|
52
|
+
|
|
53
|
+
// Stores the most recently captured frame to opportunistically encode after
|
|
54
|
+
// the current frame. Replaced frames are emitted as timings without
|
|
55
|
+
// screenshots.
|
|
56
|
+
std::mutex _lastFrameMutex;
|
|
57
|
+
std::optional<FrameData> _lastFrameData;
|
|
58
|
+
|
|
59
|
+
std::atomic<bool> _encodingInProgress;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
- (instancetype)initWithScreenshotsEnabled:(BOOL)screenshotsEnabled callback:(RCTFrameTimingCallback)callback
|
|
63
|
+
{
|
|
64
|
+
if (self = [super init]) {
|
|
65
|
+
_screenshotsEnabled = screenshotsEnabled;
|
|
66
|
+
_callback = [callback copy];
|
|
67
|
+
_frameCounter = 0;
|
|
68
|
+
_encodingQueue = dispatch_queue_create("com.facebook.react.frame-timings-observer", DISPATCH_QUEUE_SERIAL);
|
|
69
|
+
_running.store(false);
|
|
70
|
+
_lastScreenshotHash = 0;
|
|
71
|
+
_encodingInProgress.store(false);
|
|
72
|
+
}
|
|
73
|
+
return self;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
- (void)start
|
|
77
|
+
{
|
|
78
|
+
_running.store(true, std::memory_order_relaxed);
|
|
79
|
+
_frameCounter = 0;
|
|
80
|
+
_lastScreenshotHash = 0;
|
|
81
|
+
_encodingInProgress.store(false, std::memory_order_relaxed);
|
|
82
|
+
{
|
|
83
|
+
std::lock_guard<std::mutex> lock(_lastFrameMutex);
|
|
84
|
+
_lastFrameData.reset();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Emit initial frame event
|
|
88
|
+
auto now = HighResTimeStamp::now();
|
|
89
|
+
[self _emitFrameTimingWithBeginTimestamp:now endTimestamp:now];
|
|
90
|
+
|
|
91
|
+
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_displayLinkTick:)];
|
|
92
|
+
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
- (void)stop
|
|
96
|
+
{
|
|
97
|
+
_running.store(false, std::memory_order_relaxed);
|
|
98
|
+
[_displayLink invalidate];
|
|
99
|
+
_displayLink = nil;
|
|
100
|
+
{
|
|
101
|
+
std::lock_guard<std::mutex> lock(_lastFrameMutex);
|
|
102
|
+
_lastFrameData.reset();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
- (void)_displayLinkTick:(CADisplayLink *)sender
|
|
107
|
+
{
|
|
108
|
+
// CADisplayLink.timestamp and targetTimestamp are in the same timebase as
|
|
109
|
+
// CACurrentMediaTime() / mach_absolute_time(), which on Apple platforms maps
|
|
110
|
+
// to CLOCK_UPTIME_RAW — the same clock backing std::chrono::steady_clock.
|
|
111
|
+
auto beginNanos = static_cast<int64_t>(sender.timestamp * 1e9);
|
|
112
|
+
auto endNanos = static_cast<int64_t>(sender.targetTimestamp * 1e9);
|
|
113
|
+
|
|
114
|
+
auto beginTimestamp = HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
|
115
|
+
std::chrono::steady_clock::time_point(std::chrono::nanoseconds(beginNanos)));
|
|
116
|
+
auto endTimestamp = HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
|
117
|
+
std::chrono::steady_clock::time_point(std::chrono::nanoseconds(endNanos)));
|
|
118
|
+
|
|
119
|
+
[self _emitFrameTimingWithBeginTimestamp:beginTimestamp endTimestamp:endTimestamp];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
- (void)_emitFrameTimingWithBeginTimestamp:(HighResTimeStamp)beginTimestamp endTimestamp:(HighResTimeStamp)endTimestamp
|
|
123
|
+
{
|
|
124
|
+
uint64_t frameId = _frameCounter++;
|
|
125
|
+
auto threadId = static_cast<jsinspector_modern::tracing::ThreadId>(pthread_mach_thread_np(pthread_self()));
|
|
126
|
+
|
|
127
|
+
if (!_screenshotsEnabled) {
|
|
128
|
+
// Screenshots disabled - emit without screenshot
|
|
129
|
+
[self _emitFrameEventWithFrameId:frameId
|
|
130
|
+
threadId:threadId
|
|
131
|
+
beginTimestamp:beginTimestamp
|
|
132
|
+
endTimestamp:endTimestamp
|
|
133
|
+
screenshot:std::nullopt];
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
UIImage *image = [self _captureScreenshot];
|
|
138
|
+
if (image == nil) {
|
|
139
|
+
// Failed to capture (e.g. no window, duplicate hash) - emit without screenshot
|
|
140
|
+
[self _emitFrameEventWithFrameId:frameId
|
|
141
|
+
threadId:threadId
|
|
142
|
+
beginTimestamp:beginTimestamp
|
|
143
|
+
endTimestamp:endTimestamp
|
|
144
|
+
screenshot:std::nullopt];
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
FrameData frameData{image, frameId, threadId, beginTimestamp, endTimestamp};
|
|
149
|
+
|
|
150
|
+
bool expected = false;
|
|
151
|
+
if (_encodingInProgress.compare_exchange_strong(expected, true)) {
|
|
152
|
+
// Not encoding - encode this frame immediately
|
|
153
|
+
[self _encodeFrame:std::move(frameData)];
|
|
154
|
+
} else {
|
|
155
|
+
// Encoding thread busy - store current screenshot in buffer for tail-capture
|
|
156
|
+
std::optional<FrameData> oldFrame;
|
|
157
|
+
{
|
|
158
|
+
std::lock_guard<std::mutex> lock(_lastFrameMutex);
|
|
159
|
+
oldFrame = std::move(_lastFrameData);
|
|
160
|
+
_lastFrameData = std::move(frameData);
|
|
161
|
+
}
|
|
162
|
+
if (oldFrame.has_value()) {
|
|
163
|
+
// Skipped frame - emit event without screenshot
|
|
164
|
+
[self _emitFrameEventWithFrameId:oldFrame->frameId
|
|
165
|
+
threadId:oldFrame->threadId
|
|
166
|
+
beginTimestamp:oldFrame->beginTimestamp
|
|
167
|
+
endTimestamp:oldFrame->endTimestamp
|
|
168
|
+
screenshot:std::nullopt];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
- (void)_emitFrameEventWithFrameId:(uint64_t)frameId
|
|
174
|
+
threadId:(jsinspector_modern::tracing::ThreadId)threadId
|
|
175
|
+
beginTimestamp:(HighResTimeStamp)beginTimestamp
|
|
176
|
+
endTimestamp:(HighResTimeStamp)endTimestamp
|
|
177
|
+
screenshot:(std::optional<std::vector<uint8_t>>)screenshot
|
|
178
|
+
{
|
|
179
|
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
|
180
|
+
if (!self->_running.load(std::memory_order_relaxed)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
jsinspector_modern::tracing::FrameTimingSequence sequence{
|
|
184
|
+
frameId, threadId, beginTimestamp, endTimestamp, std::move(screenshot)};
|
|
185
|
+
self->_callback(std::move(sequence));
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
- (void)_encodeFrame:(FrameData)frameData
|
|
190
|
+
{
|
|
191
|
+
dispatch_async(_encodingQueue, ^{
|
|
192
|
+
if (!self->_running.load(std::memory_order_relaxed)) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
auto screenshot = [self _encodeScreenshot:frameData.image];
|
|
197
|
+
[self _emitFrameEventWithFrameId:frameData.frameId
|
|
198
|
+
threadId:frameData.threadId
|
|
199
|
+
beginTimestamp:frameData.beginTimestamp
|
|
200
|
+
endTimestamp:frameData.endTimestamp
|
|
201
|
+
screenshot:std::move(screenshot)];
|
|
202
|
+
|
|
203
|
+
// Clear encoding flag early, allowing new frames to start fresh encoding
|
|
204
|
+
// sessions
|
|
205
|
+
self->_encodingInProgress.store(false, std::memory_order_release);
|
|
206
|
+
|
|
207
|
+
// Opportunistically encode tail frame (if present) without blocking new
|
|
208
|
+
// frames
|
|
209
|
+
std::optional<FrameData> tailFrame;
|
|
210
|
+
{
|
|
211
|
+
std::lock_guard<std::mutex> lock(self->_lastFrameMutex);
|
|
212
|
+
tailFrame = std::move(self->_lastFrameData);
|
|
213
|
+
self->_lastFrameData.reset();
|
|
214
|
+
}
|
|
215
|
+
if (tailFrame.has_value()) {
|
|
216
|
+
if (!self->_running.load(std::memory_order_relaxed)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
auto tailScreenshot = [self _encodeScreenshot:tailFrame->image];
|
|
220
|
+
[self _emitFrameEventWithFrameId:tailFrame->frameId
|
|
221
|
+
threadId:tailFrame->threadId
|
|
222
|
+
beginTimestamp:tailFrame->beginTimestamp
|
|
223
|
+
endTimestamp:tailFrame->endTimestamp
|
|
224
|
+
screenshot:std::move(tailScreenshot)];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Captures a screenshot of the current window. Must be called on the main
|
|
230
|
+
// thread. Returns nil if capture fails or if the frame content is unchanged.
|
|
231
|
+
- (UIImage *)_captureScreenshot
|
|
232
|
+
{
|
|
233
|
+
UIWindow *keyWindow = [self _getKeyWindow];
|
|
234
|
+
if (keyWindow == nil) {
|
|
235
|
+
return nil;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
UIView *rootView = keyWindow.rootViewController.view ?: keyWindow;
|
|
239
|
+
CGSize viewSize = rootView.bounds.size;
|
|
240
|
+
CGSize scaledSize = CGSizeMake(viewSize.width * kScreenshotScaleFactor, viewSize.height * kScreenshotScaleFactor);
|
|
241
|
+
|
|
242
|
+
UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat];
|
|
243
|
+
format.scale = 1.0;
|
|
244
|
+
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:scaledSize format:format];
|
|
245
|
+
|
|
246
|
+
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) {
|
|
247
|
+
[rootView drawViewHierarchyInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height) afterScreenUpdates:NO];
|
|
248
|
+
}];
|
|
249
|
+
|
|
250
|
+
// Skip duplicate frames via sampled FNV-1a pixel hash
|
|
251
|
+
CGImageRef cgImage = image.CGImage;
|
|
252
|
+
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
|
|
253
|
+
uint64_t hash = 0xcbf29ce484222325ULL;
|
|
254
|
+
const uint8_t *ptr = CFDataGetBytePtr(pixelData);
|
|
255
|
+
CFIndex length = CFDataGetLength(pixelData);
|
|
256
|
+
// Use prime stride to prevent row alignment on power-of-2 pixel widths
|
|
257
|
+
for (CFIndex i = 0; i < length; i += 67) {
|
|
258
|
+
hash ^= ptr[i];
|
|
259
|
+
hash *= 0x100000001b3ULL;
|
|
260
|
+
}
|
|
261
|
+
CFRelease(pixelData);
|
|
262
|
+
|
|
263
|
+
if (hash == _lastScreenshotHash) {
|
|
264
|
+
return nil;
|
|
265
|
+
}
|
|
266
|
+
_lastScreenshotHash = hash;
|
|
267
|
+
|
|
268
|
+
return image;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
- (std::optional<std::vector<uint8_t>>)_encodeScreenshot:(UIImage *)image
|
|
272
|
+
{
|
|
273
|
+
NSData *jpegData = UIImageJPEGRepresentation(image, kScreenshotJPEGQuality);
|
|
274
|
+
if (jpegData == nil) {
|
|
275
|
+
return std::nullopt;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const auto *bytes = static_cast<const uint8_t *>(jpegData.bytes);
|
|
279
|
+
return std::vector<uint8_t>(bytes, bytes + jpegData.length);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
- (UIWindow *)_getKeyWindow
|
|
283
|
+
{
|
|
284
|
+
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
|
|
285
|
+
if (scene.activationState == UISceneActivationStateForegroundActive &&
|
|
286
|
+
[scene isKindOfClass:[UIWindowScene class]]) {
|
|
287
|
+
auto windowScene = (UIWindowScene *)scene;
|
|
288
|
+
for (UIWindow *window = nullptr in windowScene.windows) {
|
|
289
|
+
if (window.isKeyWindow) {
|
|
290
|
+
return window;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return nil;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@end
|
|
@@ -281,7 +281,9 @@ protected:
|
|
|
281
281
|
methodMap_["fixMappingOfEventPrioritiesBetweenFabricAndReact"] = MethodMetadata {.argCount = 0, .invoker = __fixMappingOfEventPrioritiesBetweenFabricAndReact};
|
|
282
282
|
methodMap_["fuseboxAssertSingleHostState"] = MethodMetadata {.argCount = 0, .invoker = __fuseboxAssertSingleHostState};
|
|
283
283
|
methodMap_["fuseboxEnabledRelease"] = MethodMetadata {.argCount = 0, .invoker = __fuseboxEnabledRelease};
|
|
284
|
+
methodMap_["fuseboxFrameRecordingEnabled"] = MethodMetadata {.argCount = 0, .invoker = __fuseboxFrameRecordingEnabled};
|
|
284
285
|
methodMap_["fuseboxNetworkInspectionEnabled"] = MethodMetadata {.argCount = 0, .invoker = __fuseboxNetworkInspectionEnabled};
|
|
286
|
+
methodMap_["fuseboxScreenshotCaptureEnabled"] = MethodMetadata {.argCount = 0, .invoker = __fuseboxScreenshotCaptureEnabled};
|
|
285
287
|
methodMap_["hideOffscreenVirtualViewsOnIOS"] = MethodMetadata {.argCount = 0, .invoker = __hideOffscreenVirtualViewsOnIOS};
|
|
286
288
|
methodMap_["overrideBySynchronousMountPropsAtMountingAndroid"] = MethodMetadata {.argCount = 0, .invoker = __overrideBySynchronousMountPropsAtMountingAndroid};
|
|
287
289
|
methodMap_["perfIssuesEnabled"] = MethodMetadata {.argCount = 0, .invoker = __perfIssuesEnabled};
|
|
@@ -718,6 +720,13 @@ private:
|
|
|
718
720
|
return bridging::callFromJs<bool>(rt, &T::fuseboxEnabledRelease, static_cast<NativeReactNativeFeatureFlagsCxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule));
|
|
719
721
|
}
|
|
720
722
|
|
|
723
|
+
static jsi::Value __fuseboxFrameRecordingEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) {
|
|
724
|
+
static_assert(
|
|
725
|
+
bridging::getParameterCount(&T::fuseboxFrameRecordingEnabled) == 1,
|
|
726
|
+
"Expected fuseboxFrameRecordingEnabled(...) to have 1 parameters");
|
|
727
|
+
return bridging::callFromJs<bool>(rt, &T::fuseboxFrameRecordingEnabled, static_cast<NativeReactNativeFeatureFlagsCxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule));
|
|
728
|
+
}
|
|
729
|
+
|
|
721
730
|
static jsi::Value __fuseboxNetworkInspectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) {
|
|
722
731
|
static_assert(
|
|
723
732
|
bridging::getParameterCount(&T::fuseboxNetworkInspectionEnabled) == 1,
|
|
@@ -725,6 +734,13 @@ private:
|
|
|
725
734
|
return bridging::callFromJs<bool>(rt, &T::fuseboxNetworkInspectionEnabled, static_cast<NativeReactNativeFeatureFlagsCxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule));
|
|
726
735
|
}
|
|
727
736
|
|
|
737
|
+
static jsi::Value __fuseboxScreenshotCaptureEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) {
|
|
738
|
+
static_assert(
|
|
739
|
+
bridging::getParameterCount(&T::fuseboxScreenshotCaptureEnabled) == 1,
|
|
740
|
+
"Expected fuseboxScreenshotCaptureEnabled(...) to have 1 parameters");
|
|
741
|
+
return bridging::callFromJs<bool>(rt, &T::fuseboxScreenshotCaptureEnabled, static_cast<NativeReactNativeFeatureFlagsCxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule));
|
|
742
|
+
}
|
|
743
|
+
|
|
728
744
|
static jsi::Value __hideOffscreenVirtualViewsOnIOS(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) {
|
|
729
745
|
static_assert(
|
|
730
746
|
bridging::getParameterCount(&T::hideOffscreenVirtualViewsOnIOS) == 1,
|
|
@@ -2257,15 +2257,6 @@ public abstract interface class com/facebook/react/devsupport/interfaces/StackFr
|
|
|
2257
2257
|
public abstract fun toJSON ()Lorg/json/JSONObject;
|
|
2258
2258
|
}
|
|
2259
2259
|
|
|
2260
|
-
public final class com/facebook/react/devsupport/interfaces/TracingState : java/lang/Enum {
|
|
2261
|
-
public static final field DISABLED Lcom/facebook/react/devsupport/interfaces/TracingState;
|
|
2262
|
-
public static final field ENABLEDINBACKGROUNDMODE Lcom/facebook/react/devsupport/interfaces/TracingState;
|
|
2263
|
-
public static final field ENABLEDINCDPMODE Lcom/facebook/react/devsupport/interfaces/TracingState;
|
|
2264
|
-
public static fun getEntries ()Lkotlin/enums/EnumEntries;
|
|
2265
|
-
public static fun valueOf (Ljava/lang/String;)Lcom/facebook/react/devsupport/interfaces/TracingState;
|
|
2266
|
-
public static fun values ()[Lcom/facebook/react/devsupport/interfaces/TracingState;
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
2260
|
public final class com/facebook/react/fabric/ComponentFactory {
|
|
2270
2261
|
public fun <init> ()V
|
|
2271
2262
|
}
|
package/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt
CHANGED
|
@@ -10,12 +10,12 @@ package com.facebook.react.devsupport
|
|
|
10
10
|
import android.content.Context
|
|
11
11
|
import com.facebook.react.bridge.UiThreadUtil
|
|
12
12
|
import com.facebook.react.common.SurfaceDelegateFactory
|
|
13
|
+
import com.facebook.react.devsupport.inspector.TracingState
|
|
13
14
|
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener
|
|
14
15
|
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager
|
|
15
16
|
import com.facebook.react.devsupport.interfaces.DevSupportManager
|
|
16
17
|
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager
|
|
17
18
|
import com.facebook.react.devsupport.interfaces.RedBoxHandler
|
|
18
|
-
import com.facebook.react.devsupport.interfaces.TracingState
|
|
19
19
|
import com.facebook.react.packagerconnection.RequestHandler
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -83,6 +83,6 @@ internal class BridgelessDevSupportManager(
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
fun tracingState(): TracingState {
|
|
86
|
-
return TracingState.
|
|
86
|
+
return TracingState.ENABLED_IN_CDP_MODE
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -52,6 +52,8 @@ import com.facebook.react.devsupport.DevServerHelper.PackagerCommandListener
|
|
|
52
52
|
import com.facebook.react.devsupport.InspectorFlags.getFuseboxEnabled
|
|
53
53
|
import com.facebook.react.devsupport.StackTraceHelper.convertJavaStackTrace
|
|
54
54
|
import com.facebook.react.devsupport.StackTraceHelper.convertJsStackTrace
|
|
55
|
+
import com.facebook.react.devsupport.inspector.TracingState
|
|
56
|
+
import com.facebook.react.devsupport.inspector.TracingStateProvider
|
|
55
57
|
import com.facebook.react.devsupport.interfaces.BundleLoadCallback
|
|
56
58
|
import com.facebook.react.devsupport.interfaces.DebuggerFrontendPanelName
|
|
57
59
|
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener
|
|
@@ -66,8 +68,6 @@ import com.facebook.react.devsupport.interfaces.PackagerStatusCallback
|
|
|
66
68
|
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager
|
|
67
69
|
import com.facebook.react.devsupport.interfaces.RedBoxHandler
|
|
68
70
|
import com.facebook.react.devsupport.interfaces.StackFrame
|
|
69
|
-
import com.facebook.react.devsupport.interfaces.TracingState
|
|
70
|
-
import com.facebook.react.devsupport.interfaces.TracingStateProvider
|
|
71
71
|
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
|
|
72
72
|
import com.facebook.react.devsupport.perfmonitor.PerfMonitorOverlayManager
|
|
73
73
|
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
|
@@ -396,21 +396,21 @@ public abstract class DevSupportManagerBase(
|
|
|
396
396
|
|
|
397
397
|
val analyzePerformanceItemString =
|
|
398
398
|
when (tracingState) {
|
|
399
|
-
TracingState.
|
|
399
|
+
TracingState.ENABLED_IN_BACKGROUND_MODE ->
|
|
400
400
|
applicationContext.getString(R.string.catalyst_performance_background)
|
|
401
|
-
TracingState.
|
|
401
|
+
TracingState.ENABLED_IN_CDP_MODE ->
|
|
402
402
|
applicationContext.getString(R.string.catalyst_performance_cdp)
|
|
403
403
|
TracingState.DISABLED ->
|
|
404
404
|
applicationContext.getString(R.string.catalyst_performance_disabled)
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
-
if (!isConnected || tracingState == TracingState.
|
|
407
|
+
if (!isConnected || tracingState == TracingState.ENABLED_IN_CDP_MODE) {
|
|
408
408
|
disabledItemKeys.add(analyzePerformanceItemString)
|
|
409
409
|
}
|
|
410
410
|
|
|
411
411
|
options[analyzePerformanceItemString] =
|
|
412
412
|
when (tracingState) {
|
|
413
|
-
TracingState.
|
|
413
|
+
TracingState.ENABLED_IN_BACKGROUND_MODE ->
|
|
414
414
|
DevOptionHandler {
|
|
415
415
|
UiThreadUtil.runOnUiThread {
|
|
416
416
|
if (reactInstanceDevHelper is PerfMonitorDevHelper) {
|
|
@@ -427,7 +427,7 @@ public abstract class DevSupportManagerBase(
|
|
|
427
427
|
if (reactInstanceDevHelper is PerfMonitorDevHelper)
|
|
428
428
|
reactInstanceDevHelper.inspectorTarget?.resumeBackgroundTrace()
|
|
429
429
|
}
|
|
430
|
-
TracingState.
|
|
430
|
+
TracingState.ENABLED_IN_CDP_MODE -> DevOptionHandler {}
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
@@ -17,7 +17,11 @@ internal object InspectorFlags {
|
|
|
17
17
|
SoLoader.loadLibrary("react_devsupportjni")
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
@DoNotStrip @JvmStatic external fun getScreenshotCaptureEnabled(): Boolean
|
|
21
|
+
|
|
20
22
|
@DoNotStrip @JvmStatic external fun getFuseboxEnabled(): Boolean
|
|
21
23
|
|
|
22
24
|
@DoNotStrip @JvmStatic external fun getIsProfilingBuild(): Boolean
|
|
25
|
+
|
|
26
|
+
@DoNotStrip @JvmStatic external fun getFrameRecordingEnabled(): Boolean
|
|
23
27
|
}
|
package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
package com.facebook.react.devsupport.inspector
|
|
9
|
+
|
|
10
|
+
internal data class FrameTimingSequence(
|
|
11
|
+
val id: Int,
|
|
12
|
+
val threadId: Int,
|
|
13
|
+
val beginTimestamp: Long,
|
|
14
|
+
val endTimestamp: Long,
|
|
15
|
+
val screenshot: ByteArray? = null,
|
|
16
|
+
)
|