Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3b618c5
feat(core): Wire TurboModulePerfLogger on iOS and Android
alwx Jun 17, 2026
97df93f
test(turbomodule): Cover perf-logger controller and JVM tracker latch
alwx Jun 18, 2026
bb976aa
Merge branch 'main' into alwx/feature/turbo-module-perf-logger
alwx Jun 18, 2026
995956f
Merge branch 'main' into alwx/feature/turbo-module-perf-logger
alwx Jun 18, 2026
be968f3
fix(turbomodule): Defer logger install until enableTurboModuleTrackin…
alwx Jun 22, 2026
8b7286b
fix(turbomodule): Publish enabled flag before lazy-installing the logger
alwx Jun 22, 2026
e3dd8b1
fix(turbomodule,android): Drop link-time --strip-all so AGP can ship …
alwx Jun 22, 2026
3131972
fix(turbomodule): Toggle tracking only after native SDK starts, guard…
alwx Jun 22, 2026
f45928a
Merge branch 'main' into alwx/feature/turbo-module-perf-logger
alwx Jun 22, 2026
542444f
fix(turbomodule,android): Lazy library load, package cpp/, shorter ch…
alwx Jun 22, 2026
3d0c73b
fix(turbomodule): Synchronize lazy lib load, lock-free hot-path sink …
alwx Jun 22, 2026
5d6f39f
fix(turbomodule): Revert hot-path raw pointer to avoid sink-swap UAF
alwx Jun 22, 2026
5c7013c
fix(turbomodule,android): Honour lazy load contract on setEnabled(false)
alwx Jun 22, 2026
f765bc3
fix(android): Reject initNativeSdk promise on native init failure
alwx Jun 22, 2026
00b77a0
fix(turbomodule): Reconcile tracking flag on every initNativeSdk
alwx Jun 23, 2026
7a08fe4
chore(sample): Enable enableTurboModuleTracking in RN sample
alwx Jun 23, 2026
8a16f7d
fix(turbomodule): Default TM tracker to isolation scope for native sync
alwx Jun 23, 2026
482ac45
fix(turbomodule,android): Close setEnabled enable/disable race
alwx Jun 23, 2026
0760761
Merge branch 'main' into alwx/feature/turbo-module-perf-logger
alwx Jun 23, 2026
0ab2761
test(turbomodule): Mock getIsolationScope in wrapTurboModule tests
alwx Jun 23, 2026
2c42d1d
fix(turbomodule): Swallow exceptions in noexcept install() to avoid s…
alwx Jun 24, 2026
edaffa0
fix(turbomodule): Use real pbxproj UUIDs, reflow cpp clang-format
alwx Jun 24, 2026
e3bbd9d
fix(turbomodule): RN 0.71 OldArch build, promise hang, parsing, insta…
alwx Jun 24, 2026
4f592a8
Merge branch 'main' into alwx/feature/turbo-module-perf-logger
alwx Jun 24, 2026
416006d
fix(turbomodule,ios): Use CFBooleanGetTypeID instead of @encode(BOOL)…
alwx Jun 24, 2026
3622bf6
fix(turbomodule): Honest isEnabled() after install failure; clearer n…
alwx Jun 24, 2026
8834bc6
fix(turbomodule,android): Gate native build on RN >= 0.75 prefab avai…
alwx Jun 24, 2026
adef511
Merge branch 'main' into alwx/feature/turbo-module-perf-logger
alwx Jun 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
## Unreleased

### Features

- Add `enableTurboModuleTracking` opt-in experimental option to enable Turbo Module performance tracking in the New Architecture ([#6307](https://github.com/getsentry/sentry-react-native/pull/6307))

### Fixes

- Apply `SENTRY_ENVIRONMENT`, `SENTRY_RELEASE` and `SENTRY_DIST` build-time overrides to the JS bundled options to match the native SDKs ([#6330](https://github.com/getsentry/sentry-react-native/pull/6330))
Expand Down
1 change: 1 addition & 0 deletions packages/core/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
!react-native.config.js
!/ios/**/*
!/android/**/*
!/cpp/**/*

# New Architecture Codegen
!src/js/NativeRNSentry.ts
Expand Down
6 changes: 5 additions & 1 deletion packages/core/RNSentry.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ Pod::Spec.new do |s|

s.preserve_paths = '*.js'

s.source_files = 'ios/**/*.{h,m,mm}'
# `cpp/` holds platform-agnostic C++ used by both iOS and Android. On iOS it
# is pulled in here; on Android it is compiled by the dedicated CMake target
# in `android/CMakeLists.txt`. The files are guarded with
# `RCT_NEW_ARCH_ENABLED` so they compile to empty TUs on Old Arch.
s.source_files = 'ios/**/*.{h,m,mm}', 'cpp/**/*.{h,cpp}'
s.public_header_files = 'ios/RNSentry.h', 'ios/RNSentrySDK.h', 'ios/RNSentryStart.h', 'ios/RNSentryVersion.h', 'ios/RNSentryBreadcrumb.h', 'ios/RNSentryReplay.h', 'ios/RNSentryReplayBreadcrumbConverter.h', 'ios/Replay/RNSentryReplayMask.h', 'ios/Replay/RNSentryReplayUnmask.h', 'ios/RNSentryTimeToDisplay.h'

s.compiler_flags = other_cflags
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.sentry.rnsentryandroidtester

import io.sentry.react.RNSentryTurboModulePerfTracker
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

/**
* Unit coverage for the JVM-side wrapper around the native perf-logger toggle.
*
* In a host JVM (where this test runs) there is no Android system loader for
* `libsentry-tm-perf-logger.so`, so any call into the native method must throw
* `UnsatisfiedLinkError`. The tracker is expected to swallow that error and
* flip an internal latch so subsequent calls short-circuit without retrying.
*
* Uses Robolectric so the `android.util.Log` call inside the tracker's `catch`
* branch resolves to a real implementation instead of the default-not-mocked
* stub the bare JUnit4 runner exposes.
*/
@RunWith(RobolectricTestRunner::class)
class RNSentryTurboModulePerfTrackerTest {
@Before
fun resetLatch() {
// Each test exercises the latch transition from scratch; without this
// reset the second test in execution order would see the latch already
// tripped from the previous one.
RNSentryTurboModulePerfTracker.resetNativeUnavailableForTests()
}

@After
fun cleanUp() {
RNSentryTurboModulePerfTracker.resetNativeUnavailableForTests()
}

@Test
fun setEnabledSwallowsUnsatisfiedLinkErrorOnFirstCall() {
// No `.so` loaded in the test JVM → the JNI symbol is missing. The
// tracker must absorb the resulting `UnsatisfiedLinkError` so the
// caller does not see a crash on a misconfigured host.
RNSentryTurboModulePerfTracker.setEnabled(true)
// Reaching this point means the error was caught, which is the contract.
assertTrue(
"after a failed link, the tracker must latch the failure",
RNSentryTurboModulePerfTracker.isNativeUnavailableForTests(),
)
}

@Test
fun subsequentCallsShortCircuitAfterLatchTrips() {
// Trip the latch via the first call.
RNSentryTurboModulePerfTracker.setEnabled(true)
assertTrue(RNSentryTurboModulePerfTracker.isNativeUnavailableForTests())

// The second call must not throw or attempt to relink. The contract is
// "exactly one UnsatisfiedLinkError per process lifetime" — anything
// else means the tracker is hammering the runtime on every setEnabled.
RNSentryTurboModulePerfTracker.setEnabled(false)
RNSentryTurboModulePerfTracker.setEnabled(true)
assertTrue(
"latch must stay tripped across repeated calls",
RNSentryTurboModulePerfTracker.isNativeUnavailableForTests(),
)
}

@Test
fun setEnabledFalseDoesNotLoadNativeLibrary() {
// The lazy-load contract: hosts that never opt in to
// `enableTurboModuleTracking` pay no shared-library cost. A bare
// `initNativeSdk` with the option absent or `false` calls
// `setEnabled(false)` from Java, and we expect this NOT to attempt
// `System.loadLibrary`. The proxy for "did we attempt the load?" is
// the `nativeUnavailable` latch — in the test JVM the load would
// fail, so if it ran we would see the latch tripped.
RNSentryTurboModulePerfTracker.setEnabled(false)
assertFalse(
"setEnabled(false) on a fresh tracker must not attempt to load the native library",
RNSentryTurboModulePerfTracker.isNativeUnavailableForTests(),
)
}

@Test
fun resetClearsTheLatch() {
RNSentryTurboModulePerfTracker.setEnabled(true)
assertTrue(RNSentryTurboModulePerfTracker.isNativeUnavailableForTests())

RNSentryTurboModulePerfTracker.resetNativeUnavailableForTests()
assertFalse(
"the @TestOnly reset must clear the latch so tests can re-exercise it",
RNSentryTurboModulePerfTracker.isNativeUnavailableForTests(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
33DEDFED2D8DC825006066E4 /* RNSentryOnDrawReporter+Test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33DEDFEC2D8DC820006066E4 /* RNSentryOnDrawReporter+Test.mm */; };
33DEDFF02D9185EB006066E4 /* RNSentryTimeToDisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33DEDFEF2D9185E3006066E4 /* RNSentryTimeToDisplayTests.swift */; };
33F58AD02977037D008F60EA /* RNSentryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33F58ACF2977037D008F60EA /* RNSentryTests.m */; };
2639D71D3BD04F17B0BAC987 /* RNSentryTurboModulePerfControllerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = E795057A6D534A80A9D06356 /* RNSentryTurboModulePerfControllerTests.mm */; };
AEFB00422CC90C4B00EC8A9A /* RNSentryBreadcrumbTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */; };
B4DEB41739F14AA38202D4D4 /* RNSentryUriValidationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E3742693F7643C2ADE1BDF2 /* RNSentryUriValidationTests.m */; };
B5859A50A3E865EF5E61465A /* libPods-RNSentryCocoaTesterTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 650CB718ACFBD05609BF2126 /* libPods-RNSentryCocoaTesterTests.a */; };
Expand Down Expand Up @@ -51,6 +52,7 @@
33F58ACF2977037D008F60EA /* RNSentryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSentryTests.m; sourceTree = "<group>"; };
3E3742693F7643C2ADE1BDF2 /* RNSentryUriValidationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryUriValidationTests.m; sourceTree = "<group>"; };
650CB718ACFBD05609BF2126 /* libPods-RNSentryCocoaTesterTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNSentryCocoaTesterTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E795057A6D534A80A9D06356 /* RNSentryTurboModulePerfControllerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RNSentryTurboModulePerfControllerTests.mm; sourceTree = "<group>"; };
E2321E7CFA55AB617247098E /* Pods-RNSentryCocoaTesterTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNSentryCocoaTesterTests.debug.xcconfig"; path = "Target Support Files/Pods-RNSentryCocoaTesterTests/Pods-RNSentryCocoaTesterTests.debug.xcconfig"; sourceTree = "<group>"; };
F48F26542EA2A481008A185E /* RNSentryEmitNewFrameEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryEmitNewFrameEvent.h; path = ../ios/RNSentryEmitNewFrameEvent.h; sourceTree = SOURCE_ROOT; };
F48F26552EA2A4D4008A185E /* RNSentryFramesTrackerListener.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryFramesTrackerListener.h; path = ../ios/RNSentryFramesTrackerListener.h; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -111,6 +113,7 @@
33F58ACF2977037D008F60EA /* RNSentryTests.m */,
3339C4802D6625570088EB3A /* RNSentryUserTests.m */,
3E3742693F7643C2ADE1BDF2 /* RNSentryUriValidationTests.m */,
E795057A6D534A80A9D06356 /* RNSentryTurboModulePerfControllerTests.mm */,
33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */,
33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */,
3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */,
Expand Down Expand Up @@ -266,6 +269,7 @@
33F58AD02977037D008F60EA /* RNSentryTests.m in Sources */,
3339C4812D6625570088EB3A /* RNSentryUserTests.m in Sources */,
B4DEB41739F14AA38202D4D4 /* RNSentryUriValidationTests.m in Sources */,
2639D71D3BD04F17B0BAC987 /* RNSentryTurboModulePerfControllerTests.mm in Sources */,
33DEDFF02D9185EB006066E4 /* RNSentryTimeToDisplayTests.swift in Sources */,
3380C6C42CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift in Sources */,
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

+ (BOOL)captureReplayWithReturnValue;

+ (BOOL)turboModuleTrackingEnabledFromOptions:(NSDictionary *)options;

#if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST
+ (BOOL)isPathUnderAllowedRootsForTesting:(NSString *)path;
#endif
Expand Down
Loading
Loading