From 9f214c72557d45b92aeb3c0e9be6c8d5ba77d35c Mon Sep 17 00:00:00 2001 From: Noah Martin Date: Thu, 2 Oct 2025 16:52:19 -0400 Subject: [PATCH 01/12] chore: Remove hang tracker sdk v9 checks --- .../SentrySDKOverrides.swift | 5 +- .../SentrySampleShared/SentrySDKWrapper.swift | 3 - Sources/Sentry/Public/SentryOptions.h | 27 +------- Sources/Sentry/SentryANRTrackingIntegration.m | 61 ++++++------------- Sources/Sentry/SentryBaseIntegration.m | 12 ---- Sources/Sentry/SentryDependencyContainer.m | 26 +++----- Sources/Sentry/SentryOptions.m | 10 +-- ...ryWatchdogTerminationTrackingIntegration.m | 9 +-- Sources/Sentry/SentyOptionsInternal.m | 5 -- .../HybridPublic/SentryDependencyContainer.h | 3 - .../Helper/SentryEnabledFeaturesBuilder.swift | 8 --- .../SentryContinuousProfilerTests.swift | 8 --- .../SentryDependencyContainerTests.swift | 36 ++--------- .../SentryEnabledFeaturesBuilderTests.swift | 4 -- .../SentryANRTrackingIntegrationTests.swift | 6 -- ...SentryFramesTrackingIntegrationTests.swift | 2 - Tests/SentryTests/SentryOptionsTest.m | 28 ++------- 17 files changed, 41 insertions(+), 212 deletions(-) diff --git a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift index f98701f99c7..dee8214659b 100644 --- a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift +++ b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift @@ -84,7 +84,6 @@ public enum SentrySDKOverrides: String, CaseIterable { public enum Performance: String, SentrySDKOverride { case disableTimeToFullDisplayTracing = "--io.sentry.performance.disable-time-to-full-display-tracing" case disablePerformanceV2 = "--io.sentry.performance.disable-performance-v2" - case disableAppHangTrackingV2 = "--io.sentry.performance.disable-app-hang-tracking-v2" case disableSessionTracking = "--io.sentry.performance.disable-automatic-session-tracking" case disableFileIOTracing = "--io.sentry.performance.disable-file-io-tracing" case disableUIVCTracing = "--io.sentry.performance.disable-uiviewcontroller-tracing" @@ -315,7 +314,7 @@ extension SentrySDKOverrides.Other { extension SentrySDKOverrides.Performance { public var overrideType: OverrideType { switch self { - case .disableTimeToFullDisplayTracing, .disablePerformanceV2, .disableAppHangTrackingV2, .disableSessionTracking, .disableFileIOTracing, .disableUIVCTracing, .disableCoreDataTracing, .disableANRTracking, .disableWatchdogTracking, .disableUITracing, .disablePrewarmedAppStartTracing, .disablePerformanceTracing: return .boolean + case .disableTimeToFullDisplayTracing, .disablePerformanceV2, .disableSessionTracking, .disableFileIOTracing, .disableUIVCTracing, .disableCoreDataTracing, .disableANRTracking, .disableWatchdogTracking, .disableUITracing, .disablePrewarmedAppStartTracing, .disablePerformanceTracing: return .boolean case .sessionTrackingIntervalMillis: return .string } } @@ -402,7 +401,7 @@ extension SentrySDKOverrides.Other { extension SentrySDKOverrides.Performance { public var ignoresDisableEverything: Bool { switch self { - case .disableTimeToFullDisplayTracing, .disablePerformanceV2, .disableAppHangTrackingV2, .disableSessionTracking, .disableFileIOTracing, .disableUIVCTracing, .disableCoreDataTracing, .disableANRTracking, .disableWatchdogTracking, .disableUITracing, .disablePrewarmedAppStartTracing, .disablePerformanceTracing: return false + case .disableTimeToFullDisplayTracing, .disablePerformanceV2, .disableSessionTracking, .disableFileIOTracing, .disableUIVCTracing, .disableCoreDataTracing, .disableANRTracking, .disableWatchdogTracking, .disableUITracing, .disablePrewarmedAppStartTracing, .disablePerformanceTracing: return false case .sessionTrackingIntervalMillis: return true } } diff --git a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift index bfa70239185..236cb7261c5 100644 --- a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift +++ b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift @@ -108,9 +108,6 @@ public struct SentrySDKWrapper { options.screenshot.maskAllText = !SentrySDKOverrides.Screenshot.disableMaskAllText.boolValue options.attachViewHierarchy = !SentrySDKOverrides.Other.disableAttachViewHierarchy.boolValue - #if !SDK_V9 - options.enableAppHangTrackingV2 = !SentrySDKOverrides.Performance.disableAppHangTrackingV2.boolValue - #endif // SDK_V9 #endif // !os(macOS) && !os(watchOS) // disable during benchmarks because we run CPU for 15 seconds at full throttle which can trigger ANRs diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index dbd9dcfbe86..287d0c17c39 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -662,34 +662,11 @@ typedef void (^SentryProfilingConfigurationBlock)(SentryProfileOptions *_Nonnull #if SENTRY_UIKIT_AVAILABLE -# if !SDK_V9 -/** - * AppHangTrackingV2 can differentiate between fully-blocking and non-fully blocking app hangs. - * fully-blocking app hang is when the main thread is stuck completely, and the app can't render a - * single frame. A non-fully-blocking app hang is when the app appears stuck to the user but can - still - * render a few frames. Fully-blocking app hangs are more actionable because the stacktrace shows - the - * exact blocking location on the main thread. As the main thread isn't completely blocked, - * non-fully-blocking app hangs can have a stacktrace that doesn't highlight the exact blocking - * location. - * - * You can use @c enableReportNonFullyBlockingAppHangs to ignore non-fully-blocking app hangs. - * - * @note This flag wins over enableAppHangTracking. When enabling both enableAppHangTracking and - enableAppHangTrackingV2, the SDK only enables enableAppHangTrackingV2 and disables - enableAppHangTracking. - */ -@property (nonatomic, assign) BOOL enableAppHangTrackingV2; - -# endif // !SDK_V9 - /** * When enabled the SDK reports non-fully-blocking app hangs. A non-fully-blocking app hang is when - * the app appears stuck to the user but can still render a few frames. For more information see @c - * enableAppHangTrackingV2. + * the app appears stuck to the user but can still render a few frames. * - * @note The default is @c YES. This feature only works when @c enableAppHangTrackingV2 is enabled. + * @note The default is @c YES. */ @property (nonatomic, assign) BOOL enableReportNonFullyBlockingAppHangs; diff --git a/Sources/Sentry/SentryANRTrackingIntegration.m b/Sources/Sentry/SentryANRTrackingIntegration.m index 0b07fb757c2..172a6e0dc67 100644 --- a/Sources/Sentry/SentryANRTrackingIntegration.m +++ b/Sources/Sentry/SentryANRTrackingIntegration.m @@ -46,14 +46,8 @@ - (BOOL)installWithOptions:(SentryOptions *)options } #if SENTRY_HAS_UIKIT -# if SDK_V9 - BOOL isV2Enabled = YES; -# else - BOOL isV2Enabled = options.enableAppHangTrackingV2; -# endif // SDK_V9 self.tracker = - [SentryDependencyContainer.sharedInstance getANRTracker:options.appHangTimeoutInterval - isV2Enabled:isV2Enabled]; + [SentryDependencyContainer.sharedInstance getANRTracker:options.appHangTimeoutInterval]; #else self.tracker = [SentryDependencyContainer.sharedInstance getANRTracker:options.appHangTimeoutInterval]; @@ -158,48 +152,29 @@ - (void)anrDetectedWithType:(enum SentryANRType)type getDebugImagesFromCacheForThreads:SENTRY_UNWRAP_NULLABLE(NSArray, event.threads)]; #if SENTRY_HAS_UIKIT -# if SDK_V9 - BOOL isV2Enabled = YES; -# else - BOOL isV2Enabled = self.options.enableAppHangTrackingV2; -# endif // SDK_V9 - - // We only measure app hang duration for V2. - // For V1, we directly capture the app hang event. - if (isV2Enabled) { - // We only temporarily store the app hang duration info, so we can change the error message - // when either sending a normal or fatal app hang event. Otherwise, we would have to rely on - // string parsing to retrieve the app hang duration info from the error message. - mechanism.data = @{ SentryANRMechanismDataAppHangDuration : appHangDurationInfo }; - - // We need to apply the scope now because if the app hang turns into a fatal one, - // we would lose the scope. Furthermore, we want to know in which state the app was when the - // app hang started. - SentryScope *scope = [SentrySDKInternal currentHub].scope; - SentryOptions *options = SentrySDKInternal.options; - if (scope != nil && options != nil) { - [scope applyToEvent:event maxBreadcrumb:options.maxBreadcrumbs]; - } - - [self.fileManager storeAppHangEvent:event]; - } else { -#endif // SENTRY_HAS_UIKIT - [SentrySDK captureEvent:event]; -#if SENTRY_HAS_UIKIT + // We only temporarily store the app hang duration info, so we can change the error message + // when either sending a normal or fatal app hang event. Otherwise, we would have to rely on + // string parsing to retrieve the app hang duration info from the error message. + mechanism.data = @{ SentryANRMechanismDataAppHangDuration : appHangDurationInfo }; + + // We need to apply the scope now because if the app hang turns into a fatal one, + // we would lose the scope. Furthermore, we want to know in which state the app was when the + // app hang started. + SentryScope *scope = [SentrySDKInternal currentHub].scope; + SentryOptions *options = SentrySDKInternal.options; + if (scope != nil && options != nil) { + [scope applyToEvent:event maxBreadcrumb:options.maxBreadcrumbs]; } -#endif // SENTRY_UIKIT_AVAILABLE + + [self.fileManager storeAppHangEvent:event]; +#else + [SentrySDK captureEvent:event]; +#endif } - (void)anrStoppedWithResult:(SentryANRStoppedResult *_Nullable)result { #if SENTRY_HAS_UIKIT - // We only measure app hang duration for V2, and therefore ignore V1. -# if !SDK_V9 - if (!self.options.enableAppHangTrackingV2) { - return; - } -# endif // !SDK_V9 - if (result == nil) { SENTRY_LOG_WARN(@"ANR stopped for V2 but result was nil.") return; diff --git a/Sources/Sentry/SentryBaseIntegration.m b/Sources/Sentry/SentryBaseIntegration.m index ee0b984d65b..a4749c860a2 100644 --- a/Sources/Sentry/SentryBaseIntegration.m +++ b/Sources/Sentry/SentryBaseIntegration.m @@ -77,17 +77,10 @@ - (BOOL)shouldBeEnabledWithOptions:(SentryOptions *)options if (integrationOptions & kIntegrationOptionEnableAppHangTracking) { #if SENTRY_HAS_UIKIT -# if SDK_V9 if (!options.enableAppHangTracking) { [self logWithOptionName:@"enableAppHangTracking"]; return NO; } -# else - if (!options.enableAppHangTracking && !options.enableAppHangTrackingV2) { - [self logWithOptionName:@"enableAppHangTracking && enableAppHangTrackingV2"]; - return NO; - } -# endif #else if (!options.enableAppHangTracking) { [self logWithOptionName:@"enableAppHangTracking"]; @@ -186,14 +179,9 @@ - (BOOL)shouldBeEnabledWithOptions:(SentryOptions *)options BOOL performanceDisabled = !options.enableAutoPerformanceTracing || !options.isTracingEnabled; BOOL appHangsV2Disabled = options.isAppHangTrackingV2Disabled; -# if SDK_V9 // The V9 watchdog tracker uses the frames tracker, so frame tracking // must be enabled if watchdog tracking is enabled. BOOL watchdogDisabled = !options.enableWatchdogTerminationTracking; -# else - // Before V9 this should have no effect so set it to YES - BOOL watchdogDisabled = YES; -# endif // SDK_V9 if (performanceDisabled && appHangsV2Disabled && watchdogDisabled) { if (appHangsV2Disabled) { diff --git a/Sources/Sentry/SentryDependencyContainer.m b/Sources/Sentry/SentryDependencyContainer.m index 84189e63688..bb580c72aa1 100644 --- a/Sources/Sentry/SentryDependencyContainer.m +++ b/Sources/Sentry/SentryDependencyContainer.m @@ -257,30 +257,22 @@ - (SentryCrash *)crashReporter SENTRY_THREAD_SANITIZER_DOUBLE_CHECKED_LOCK - (id)getANRTracker:(NSTimeInterval)timeout SENTRY_THREAD_SANITIZER_DOUBLE_CHECKED_LOCK { +#if SENTRY_HAS_UIKIT + SENTRY_LAZY_INIT(_anrTracker, + [[[SentryANRTrackerV2 alloc] initWithTimeoutInterval:timeout + crashWrapper:self.crashWrapper + dispatchQueueWrapper:self.dispatchQueueWrapper + threadWrapper:self.threadWrapper + framesTracker:self.framesTracker] asProtocol]); +#else SENTRY_LAZY_INIT(_anrTracker, [[[SentryANRTrackerV1 alloc] initWithTimeoutInterval:timeout crashWrapper:self.crashWrapper dispatchQueueWrapper:self.dispatchQueueWrapper threadWrapper:self.threadWrapper] asProtocol]); +#endif } -#if SENTRY_HAS_UIKIT -- (id)getANRTracker:(NSTimeInterval)timeout - isV2Enabled:(BOOL)isV2Enabled SENTRY_THREAD_SANITIZER_DOUBLE_CHECKED_LOCK -{ - if (isV2Enabled) { - SENTRY_LAZY_INIT(_anrTracker, - [[[SentryANRTrackerV2 alloc] initWithTimeoutInterval:timeout - crashWrapper:self.crashWrapper - dispatchQueueWrapper:self.dispatchQueueWrapper - threadWrapper:self.threadWrapper - framesTracker:self.framesTracker] asProtocol]); - } else { - return [self getANRTracker:timeout]; - } -} -#endif // SENTRY_HAS_UIKIT - #if SENTRY_TARGET_REPLAY_SUPPORTED - (nonnull SentryScreenshotSource *)screenshotSource SENTRY_THREAD_SANITIZER_DOUBLE_CHECKED_LOCK { diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 78e4ad2931b..863040cb83c 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -111,9 +111,6 @@ - (instancetype)init self.enableUserInteractionTracing = YES; self.idleTimeout = SentryTracerDefaultTimeout; self.enablePreWarmedAppStartTracing = NO; -# if !SDK_V9 - self.enableAppHangTrackingV2 = NO; -# endif // !SDK_V9 self.enableReportNonFullyBlockingAppHangs = YES; #endif // SENTRY_HAS_UIKIT @@ -501,12 +498,7 @@ - (void)setEnableSpotlight:(BOOL)value #if SENTRY_HAS_UIKIT - (BOOL)isAppHangTrackingV2Disabled { -# if SDK_V9 - BOOL isV2Enabled = self.enableAppHangTracking; -# else - BOOL isV2Enabled = self.enableAppHangTrackingV2; -# endif // SDK_V9 - return !isV2Enabled || self.appHangTimeoutInterval <= 0; + return !self.enableAppHangTracking || self.appHangTimeoutInterval <= 0; } #endif // SENTRY_HAS_UIKIT diff --git a/Sources/Sentry/SentryWatchdogTerminationTrackingIntegration.m b/Sources/Sentry/SentryWatchdogTerminationTrackingIntegration.m index f7c0abc200b..b1840b1bb92 100644 --- a/Sources/Sentry/SentryWatchdogTerminationTrackingIntegration.m +++ b/Sources/Sentry/SentryWatchdogTerminationTrackingIntegration.m @@ -75,15 +75,8 @@ - (BOOL)installWithOptions:(SentryOptions *)options [self.tracker start]; -# if SDK_V9 - BOOL isV2Enabled = YES; -# else - BOOL isV2Enabled = options.enableAppHangTrackingV2; -# endif // SDK_V9 - self.anrTracker = - [SentryDependencyContainer.sharedInstance getANRTracker:options.appHangTimeoutInterval - isV2Enabled:isV2Enabled]; + [SentryDependencyContainer.sharedInstance getANRTracker:options.appHangTimeoutInterval]; [self.anrTracker addListener:self]; self.appStateManager = appStateManager; diff --git a/Sources/Sentry/SentyOptionsInternal.m b/Sources/Sentry/SentyOptionsInternal.m index 2f8a255ddca..b92854da580 100644 --- a/Sources/Sentry/SentyOptionsInternal.m +++ b/Sources/Sentry/SentyOptionsInternal.m @@ -281,11 +281,6 @@ + (BOOL)validateOptions:(NSDictionary *)options [self setBool:options[@"enablePreWarmedAppStartTracing"] block:^(BOOL value) { sentryOptions.enablePreWarmedAppStartTracing = value; }]; -# if !SDK_V9 - [self setBool:options[@"enableAppHangTrackingV2"] - block:^(BOOL value) { sentryOptions.enableAppHangTrackingV2 = value; }]; -# endif // !SDK_V9 - [self setBool:options[@"enableReportNonFullyBlockingAppHangs"] block:^(BOOL value) { sentryOptions.enableReportNonFullyBlockingAppHangs = value; }]; diff --git a/Sources/Sentry/include/HybridPublic/SentryDependencyContainer.h b/Sources/Sentry/include/HybridPublic/SentryDependencyContainer.h index 483f18aa267..4e21d88d6ac 100644 --- a/Sources/Sentry/include/HybridPublic/SentryDependencyContainer.h +++ b/Sources/Sentry/include/HybridPublic/SentryDependencyContainer.h @@ -113,9 +113,6 @@ SENTRY_NO_INIT @property (nonatomic, strong) SentryDebugImageProvider *debugImageProvider; - (id)getANRTracker:(NSTimeInterval)timeout; -#if SENTRY_HAS_UIKIT -- (id)getANRTracker:(NSTimeInterval)timeout isV2Enabled:(BOOL)isV2Enabled; -#endif // SENTRY_HAS_UIKIT - (nullable id)application; diff --git a/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift b/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift index 4df962e5898..9ffaddff207 100644 --- a/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift +++ b/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift @@ -44,14 +44,6 @@ import Foundation if options.swiftAsyncStacktraces { features.append("swiftAsyncStacktraces") } - -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - #if !SDK_V9 - if options.enableAppHangTrackingV2 { - features.append("appHangTrackingV2") - } - #endif // !SDK_V9 -#endif //os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) if options.enablePersistingTracesWhenCrashing { features.append("persistingTracesWhenCrashing") diff --git a/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift b/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift index b88b5b86855..b1c3e40ccb2 100644 --- a/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift +++ b/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift @@ -80,15 +80,7 @@ final class SentryContinuousProfilerTests: XCTestCase { #if !os(macOS) - func testStopsFramesTracker_WhenAutoPerformanceAndAppHangsV2Disabled() throws { - fixture.options.enableAutoPerformanceTracing = false - try performContinuousProfilingTest() - - XCTAssertFalse(SentryDependencyContainer.sharedInstance().framesTracker.isRunning) - } - func testDoesNotStopFramesTracker_WhenAppHangsV2Enabled() throws { - fixture.options.enableAppHangTrackingV2 = true try performContinuousProfilingTest() XCTAssertTrue(SentryDependencyContainer.sharedInstance().framesTracker.isRunning) diff --git a/Tests/SentryTests/Helper/SentryDependencyContainerTests.swift b/Tests/SentryTests/Helper/SentryDependencyContainerTests.swift index 518756c3b6e..7e944097677 100644 --- a/Tests/SentryTests/Helper/SentryDependencyContainerTests.swift +++ b/Tests/SentryTests/Helper/SentryDependencyContainerTests.swift @@ -20,42 +20,13 @@ final class SentryDependencyContainerTests: XCTestCase { } func testGetANRTrackerV2() { - let instance = SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: true) + let instance = SentryDependencyContainer.sharedInstance().getANRTracker(2.0) XCTAssertTrue(instance is SentryANRTrackerV2) SentryDependencyContainer.reset() } - - func testGetANRTrackerV1() { - let instance = SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: false) - XCTAssertTrue(instance is SentryANRTrackerV1) - - SentryDependencyContainer.reset() - } - - func testGetANRTrackerV2AndThenV1_FirstCalledVersionStaysTheSame() { - let instance1 = SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: true) - XCTAssertTrue(instance1 is SentryANRTrackerV2) - - let instance2 = SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: false) - XCTAssertTrue(instance2 is SentryANRTrackerV2) - - SentryDependencyContainer.reset() - } - - func testGetANRTrackerV1AndThenV2_FirstCalledVersionStaysTheSame() { - let instance1 = SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: false) - XCTAssertTrue(instance1 is SentryANRTrackerV1) - - let instance2 = SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: true) - XCTAssertTrue(instance2 is SentryANRTrackerV1) - - SentryDependencyContainer.reset() - } - -#endif - +#else func testGetANRTracker_ReturnsV1() { let instance = SentryDependencyContainer.sharedInstance().getANRTracker(2.0) @@ -63,6 +34,7 @@ final class SentryDependencyContainerTests: XCTestCase { SentryDependencyContainer.reset() } +#endif /** * This test helps to find threading issues. If you run it once it detects obvious threading issues. Some rare edge cases @@ -121,7 +93,7 @@ final class SentryDependencyContainerTests: XCTestCase { XCTAssertNotNil(SentryDependencyContainer.sharedInstance().getANRTracker(2.0)) #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - XCTAssertNotNil(SentryDependencyContainer.sharedInstance().getANRTracker(2.0, isV2Enabled: true)) + XCTAssertNotNil(SentryDependencyContainer.sharedInstance().getANRTracker(2.0)) #endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) #if os(iOS) || os(macOS) || targetEnvironment(macCatalyst) diff --git a/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift b/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift index 4c5917a1531..cf4ffe0f3d8 100644 --- a/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift +++ b/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift @@ -36,10 +36,6 @@ final class SentryEnabledFeaturesBuilderTests: XCTestCase { #endif // canImport(UIKit) #endif // os(iOS) || os(tvOS) -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - options.enableAppHangTrackingV2 = true -#endif //os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - // -- Act -- let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options) diff --git a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift index 504c0378d62..acee107daa2 100644 --- a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift @@ -81,7 +81,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func test_enableAppHangTrackingV2_UsesV2Tracker() { let options = Options() options.enableAppHangTracking = true - options.enableAppHangTrackingV2 = true sut = SentryANRTrackingIntegration() let result = sut.install(with: options) @@ -748,11 +747,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { self.crashWrapper.internalIsBeingTraced = isBeingTraced self.crashWrapper.internalCrashedLastLaunch = crashedLastLaunch sut = SentryANRTrackingIntegration() -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - if enableV2 { - self.options.enableAppHangTrackingV2 = true - } -#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) sut.install(with: self.options) } diff --git a/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift index aa633005e9e..5cd759192f5 100644 --- a/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift @@ -49,7 +49,6 @@ class SentryFramesTrackingIntegrationTests: XCTestCase { func testAppHangV2Enabled_MeasuresFrames() { let options = fixture.options - options.enableAppHangTrackingV2 = true sut.install(with: options) XCTAssertNotNil(Dynamic(sut).tracker.asObject) @@ -57,7 +56,6 @@ class SentryFramesTrackingIntegrationTests: XCTestCase { func testAppHangV2Enabled_ButIntervalZero_DoestNotMeasuresFrames() { let options = fixture.options - options.enableAppHangTrackingV2 = true options.appHangTimeoutInterval = 0.0 sut.install(with: options) diff --git a/Tests/SentryTests/SentryOptionsTest.m b/Tests/SentryTests/SentryOptionsTest.m index 93740008697..1dd9e08dbd1 100644 --- a/Tests/SentryTests/SentryOptionsTest.m +++ b/Tests/SentryTests/SentryOptionsTest.m @@ -938,11 +938,6 @@ - (void)testEnableAppHangTracking #if SENTRY_UIKIT_AVAILABLE -- (void)testEnableAppHangTrackingV2 -{ - [self testBooleanField:@"enableAppHangTrackingV2" defaultValue:NO]; -} - - (void)testEnableReportNonFullyBlockingAppHangs { [self testBooleanField:@"enableReportNonFullyBlockingAppHangs" defaultValue:YES]; @@ -1531,33 +1526,18 @@ - (void)testSpotlightUrl } #if SENTRY_HAS_UIKIT -- (void)testIsAppHangTrackingV2Disabled_WhenBothOptionsDisabled +- (void)testIsAppHangTrackingV2Disabled_WhenOptionDisabled { - SentryOptions *options = [self - getValidOptions:@{ @"enableAppHangTrackingV2" : @NO, @"appHangTimeoutInterval" : @0 }]; - XCTAssertTrue(options.isAppHangTrackingV2Disabled); -} - -- (void)testIsAppHangTrackingV2Disabled_WhenOnlyEnableAppHangTrackingV2Disabled -{ - SentryOptions *options = [self - getValidOptions:@{ @"enableAppHangTrackingV2" : @NO, @"appHangTimeoutInterval" : @2.0 }]; + SentryOptions *options = [self getValidOptions:@{ @"appHangTimeoutInterval" : @0 }]; XCTAssertTrue(options.isAppHangTrackingV2Disabled); } - (void)testIsAppHangTrackingV2Disabled_WhenOnlyAppHangTimeoutIntervalZero { - SentryOptions *options = [self - getValidOptions:@{ @"enableAppHangTrackingV2" : @YES, @"appHangTimeoutInterval" : @0 }]; + SentryOptions *options = + [self getValidOptions:@{ @"enableAppHangTracking" : @YES, @"appHangTimeoutInterval" : @0 }]; XCTAssertTrue(options.isAppHangTrackingV2Disabled); } - -- (void)testIsAppHangTrackingV2Disabled_WhenBothOptionsEnabled -{ - SentryOptions *options = [self - getValidOptions:@{ @"enableAppHangTrackingV2" : @YES, @"appHangTimeoutInterval" : @2.0 }]; - XCTAssertFalse(options.isAppHangTrackingV2Disabled); -} #endif // SENTRY_HAS_UIKIT #pragma mark - Private From 4a4eeaecfacffb139c1ef16acaf1f3526e28db34 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Mon, 20 Oct 2025 09:46:22 +0200 Subject: [PATCH 02/12] build failure --- Samples/iOS-Swift/iOS-Swift-UITests/ViewLifecycleUITests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/iOS-Swift/iOS-Swift-UITests/ViewLifecycleUITests.swift b/Samples/iOS-Swift/iOS-Swift-UITests/ViewLifecycleUITests.swift index f1581ae5357..681c158bbfc 100644 --- a/Samples/iOS-Swift/iOS-Swift-UITests/ViewLifecycleUITests.swift +++ b/Samples/iOS-Swift/iOS-Swift-UITests/ViewLifecycleUITests.swift @@ -11,7 +11,7 @@ class ViewLifecycleUITests: BaseUITest { super.setUp() launchApp(args: [ SentrySDKOverrides.Performance.disableTimeToFullDisplayTracing.rawValue, - SentrySDKOverrides.Performance.disableAppHangTrackingV2.rawValue + SentrySDKOverrides.Performance.disableANRTracking.rawValue ]) } From 4152d9d81e6d177e9f54a98dca8237df33b79e37 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Mon, 20 Oct 2025 10:02:03 +0200 Subject: [PATCH 03/12] fix on macos --- .../SentryANRTrackingIntegrationTests.swift | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift index 5cdd628dd24..3c09b63561e 100644 --- a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift @@ -48,12 +48,16 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertNil(Dynamic(sut).tracker.asAnyObject) } - func testWhenNoDebuggerAttached_TrackerInitialized() { + func testWhenNoDebuggerAttached_TrackerInitialized() throws { givenInitializedTracker() - let tracker = Dynamic(sut).tracker.asAnyObject - XCTAssertNotNil(tracker) - XCTAssertTrue(tracker is SentryANRTrackerV1) + let tracker = try XCTUnwrap(Dynamic(sut).tracker.asAnyObject) + +#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) + XCTAssertTrue(tracker is SentryANRTrackerV2, "Expected SentryANRTrackerV2, but got \(type(of: tracker))") +#else + XCTAssertTrue(tracker is SentryANRTrackerV1, "Expected SentryANRTrackerV1 on macOS, but got \(type(of: tracker))") +#endif } func test_enableAppHangsTracking_Disabled() { @@ -76,23 +80,9 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertFalse(result) } - -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - func test_enableAppHangTrackingV2_UsesV2Tracker() { - let options = Options() - options.enableAppHangTracking = true - - sut = SentryANRTrackingIntegration() - let result = sut.install(with: options) - XCTAssertTrue(result) - let tracker = Dynamic(sut).tracker.asAnyObject - XCTAssertNotNil(tracker) - XCTAssertTrue(tracker is SentryANRTrackerV2) - } -#endif - - func testANRDetected_EventCaptured() throws { +#if os(macOS) + func testV1_ANRDetected_EventCaptured() throws { setUpThreadInspector() givenInitializedTracker() @@ -133,7 +123,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { } } - func testANRDetected_FullyBlocking_EventCaptured() throws { + func testV1_ANRDetected_FullyBlocking_EventCaptured() throws { setUpThreadInspector() givenInitializedTracker() @@ -174,7 +164,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { } } - func testANRDetected_NonFullyBlocked_EventCaptured() throws { + func testV1_ANRDetected_NonFullyBlocked_EventCaptured() throws { setUpThreadInspector() givenInitializedTracker() @@ -216,7 +206,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { } } - func testANRDetectedV1_Unknown_EventCaptured() throws { + func testV1_ANRDetected_Unknown_EventCaptured() throws { setUpThreadInspector() givenInitializedTracker() @@ -257,7 +247,8 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(eventDebugImage.uuid, TestData.debugImage.uuid) } } - +#endif // os(macOS) + #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) func testANRDetected_NonFullyBlockedDisabled_EventNotCaptured() throws { fixture.options.enableReportNonFullyBlockingAppHangs = false From 325c6860f9b39dafdbc4632cdc76147f4bdfa205 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Mon, 20 Oct 2025 10:11:12 +0200 Subject: [PATCH 04/12] fixes --- .../SentryANRTrackingIntegrationTests.swift | 73 +++++++++---------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift index 3c09b63561e..7d423ff4cc4 100644 --- a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift @@ -247,6 +247,22 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(eventDebugImage.uuid, TestData.debugImage.uuid) } } + + func testANRDetected_DetectingPausedResumed_EventCaptured() throws { + givenInitializedTracker() + setUpThreadInspector() + sut.pauseAppHangTracking() + sut.resumeAppHangTracking() + + Dynamic(sut).anrDetectedWithType(SentryANRType.unknown) + + try assertEventWithScopeCaptured { event, _, _ in + XCTAssertNotNil(event) + let ex = try XCTUnwrap(event?.exceptions?.first, "ANR Exception not found") + + XCTAssertEqual(ex.mechanism?.type, "AppHang") + } + } #endif // os(macOS) #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) @@ -270,26 +286,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { assertNoEventCaptured() } - - func testANRDetected_DetectingPausedResumed_EventCaptured() throws { - givenInitializedTracker() - setUpThreadInspector() - sut.pauseAppHangTracking() - sut.resumeAppHangTracking() - - Dynamic(sut).anrDetectedWithType(SentryANRType.unknown) - - try assertEventWithScopeCaptured { event, _, _ in - XCTAssertNotNil(event) - guard let ex = event?.exceptions?.first else { - XCTFail("ANR Exception not found") - return - } - - XCTAssertEqual(ex.mechanism?.type, "AppHang") - } - } - + func testCallPauseResumeOnMultipleThreads_DoesNotCrash() { givenInitializedTracker() @@ -349,7 +346,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRDetected_DoesNotCaptureEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() // Act Dynamic(sut).anrDetectedWithType(SentryANRType.nonFullyBlocking) @@ -361,7 +358,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRStopped_DoesCaptureEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.fullyBlocking) @@ -423,7 +420,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2Detected_PauseCalled_ANRStopped_DoesCaptureEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.fullyBlocking) @@ -482,7 +479,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRStopped_EmptyEventStored_DoesCaptureEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.fullyBlocking) @@ -499,7 +496,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRDetected_StopNotCalled_SendsFatalANROnNextInstall() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.nonFullyBlocking) @@ -509,7 +506,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { } // Act - givenInitializedTracker(enableV2: true) + givenInitializedTracker() // Assert try assertFatalEventWithScope { event, _ in @@ -539,13 +536,13 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRDetected_PauseCalledButStopNotCalled_SendsFatalANROnNextInstall() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.nonFullyBlocking) sut.pauseAppHangTracking() // Act - givenInitializedTracker(enableV2: true) + givenInitializedTracker() sut.pauseAppHangTracking() // Assert @@ -576,7 +573,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRDetected_StopNotCalledAndAbnormalSession_SendsFatalAppHangOnNextInstall() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.nonFullyBlocking) @@ -590,7 +587,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { SentrySDKInternal.currentHub().client()?.fileManager.storeAbnormalSession(abnormalSession) // Act - givenInitializedTracker(enableV2: true) + givenInitializedTracker() // Assert let client = try XCTUnwrap(SentrySDKInternal.currentHub().getClient() as? TestClient) @@ -627,12 +624,12 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRDetected_StopNotCalledAndCrashed_SendsNormalAppHangEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.fullyBlocking) // Act - givenInitializedTracker(crashedLastLaunch: true, enableV2: true) + givenInitializedTracker(crashedLastLaunch: true) // Assert try assertEventWithScopeCaptured { event, scope, _ in @@ -649,12 +646,12 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_StoredApHangEventWithNoException_NoEventCaptured() throws { // Arrange - givenInitializedTracker(enableV2: true) + givenInitializedTracker() let event = Event() SentrySDKInternal.currentHub().client()?.fileManager.storeAppHang(event) // Act - givenInitializedTracker(enableV2: true) + givenInitializedTracker() // Assert assertNoEventCaptured() @@ -663,7 +660,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRStopped_DoesDeleteTheAppHangEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.fullyBlocking) let result = SentryANRStoppedResult(minDuration: 1.849, maxDuration: 2.251) @@ -682,7 +679,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRStopped_ButEventDeleted_DoesNotCaptureEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() Dynamic(sut).anrDetectedWithType(SentryANRType.nonFullyBlocking) SentrySDKInternal.currentHub().client()?.fileManager.deleteAppHangEvent() @@ -698,7 +695,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testV2_ANRStoppedWithNilResult_DoesNotCaptureEvent() throws { // Arrange setUpThreadInspector() - givenInitializedTracker(enableV2: true) + givenInitializedTracker() // Act Dynamic(sut).anrStoppedWithResult(nil) @@ -725,7 +722,7 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertFalse(Event().isAppHangEvent) } - private func givenInitializedTracker(isBeingTraced: Bool = false, crashedLastLaunch: Bool = false, enableV2: Bool = false) { + private func givenInitializedTracker(isBeingTraced: Bool = false, crashedLastLaunch: Bool = false) { givenSdkWithHub() SentrySDK.configureScope { scope in From 8fa1cf59e3d47a965eedf0445a3da710c4ad2723 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Mon, 20 Oct 2025 11:14:47 +0200 Subject: [PATCH 05/12] fix frames tracker tests --- Sources/Sentry/SentryBaseIntegration.m | 13 ++++++------- Sources/Sentry/SentryOptions.m | 2 +- Sources/Sentry/SentryProfiler.mm | 6 +++--- Sources/Sentry/include/SentryOptions+Private.h | 2 +- .../SentryFramesTrackingIntegrationTests.swift | 18 +++++++----------- Tests/SentryTests/SentryOptionsTest.m | 8 ++++---- 6 files changed, 22 insertions(+), 27 deletions(-) diff --git a/Sources/Sentry/SentryBaseIntegration.m b/Sources/Sentry/SentryBaseIntegration.m index 1efb626ed5d..bcecd63fdea 100644 --- a/Sources/Sentry/SentryBaseIntegration.m +++ b/Sources/Sentry/SentryBaseIntegration.m @@ -176,14 +176,15 @@ - (BOOL)shouldBeEnabledWithOptions:(SentryOptions *)options #if SENTRY_HAS_UIKIT BOOL performanceDisabled = !options.enableAutoPerformanceTracing || !options.isTracingEnabled; - BOOL appHangsV2Disabled = options.isAppHangTrackingV2Disabled; - // The V9 watchdog tracker uses the frames tracker, so frame tracking + BOOL appHangsDisabled = options.isAppHangTrackingDisabled; + + // The watchdog tracker uses the frames tracker, so frame tracking // must be enabled if watchdog tracking is enabled. BOOL watchdogDisabled = !options.enableWatchdogTerminationTracking; - if (performanceDisabled && appHangsV2Disabled && watchdogDisabled) { - if (appHangsV2Disabled) { - SENTRY_LOG_DEBUG(@"Not going to enable %@ because enableAppHangTrackingV2 is " + if (performanceDisabled && appHangsDisabled && watchdogDisabled) { + if (appHangsDisabled) { + SENTRY_LOG_DEBUG(@"Not going to enable %@ because enableAppHangTracking is " @"disabled or the appHangTimeoutInterval is 0.", self.integrationName); } @@ -194,14 +195,12 @@ - (BOOL)shouldBeEnabledWithOptions:(SentryOptions *)options self.integrationName); } -# if SDK_V9 if (watchdogDisabled) { SENTRY_LOG_DEBUG( @"Not going to enable %@ because enableWatchdogTerminationTracking " @"is disabled.", self.integrationName); } -# endif // SKD_V9 return NO; } diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index fe5e6bf4a1d..48ebc47c3c6 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -455,7 +455,7 @@ - (void)setEnableSpotlight:(BOOL)value } #if SENTRY_HAS_UIKIT -- (BOOL)isAppHangTrackingV2Disabled +- (BOOL)isAppHangTrackingDisabled { return !self.enableAppHangTracking || self.appHangTimeoutInterval <= 0; } diff --git a/Sources/Sentry/SentryProfiler.mm b/Sources/Sentry/SentryProfiler.mm index 75186133aa5..b671965657c 100644 --- a/Sources/Sentry/SentryProfiler.mm +++ b/Sources/Sentry/SentryProfiler.mm @@ -247,10 +247,10 @@ - (void)stopForReason:(SentryProfilerTruncationReason)reason BOOL autoPerformanceTracingDisabled = ![[[[SentrySDKInternal currentHub] getClient] options] enableAutoPerformanceTracing]; - BOOL appHangsV2Disabled = - [[[[SentrySDKInternal currentHub] getClient] options] isAppHangTrackingV2Disabled]; + BOOL appHangsDisabled = + [[[[SentrySDKInternal currentHub] getClient] options] isAppHangTrackingDisabled]; - if (autoPerformanceTracingDisabled && appHangsV2Disabled) { + if (autoPerformanceTracingDisabled && appHangsDisabled) { sentry_stopFramesTracker(); } # endif // SENTRY_HAS_UIKIT diff --git a/Sources/Sentry/include/SentryOptions+Private.h b/Sources/Sentry/include/SentryOptions+Private.h index caf3caf05b1..fae56bbbcd1 100644 --- a/Sources/Sentry/include/SentryOptions+Private.h +++ b/Sources/Sentry/include/SentryOptions+Private.h @@ -53,7 +53,7 @@ FOUNDATION_EXPORT NSString *const kSentryDefaultEnvironment; SENTRY_EXTERN BOOL sentry_isValidSampleRate(NSNumber *sampleRate); #if SENTRY_HAS_UIKIT -- (BOOL)isAppHangTrackingV2Disabled; +- (BOOL)isAppHangTrackingDisabled; #endif // SENTRY_HAS_UIKIT @end diff --git a/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift index 7751b93a494..a5b8cfca495 100644 --- a/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/Performance/FramesTracking/SentryFramesTrackingIntegrationTests.swift @@ -48,16 +48,17 @@ class SentryFramesTrackingIntegrationTests: XCTestCase { XCTAssertNotNil(Dynamic(sut).tracker.asObject) } - func testAppHangV2Enabled_MeasuresFrames() { + func testAppHangEnabled_MeasuresFrames() { let options = fixture.options sut.install(with: options) XCTAssertNotNil(Dynamic(sut).tracker.asObject) } - func testAppHangV2Enabled_ButIntervalZero_DoestNotMeasuresFrames() { + func testAppHangEnabled_ButIntervalZero_DoestNotMeasuresFrames() { let options = fixture.options options.appHangTimeoutInterval = 0.0 + options.enableWatchdogTerminationTracking = false sut.install(with: options) XCTAssertNil(Dynamic(sut).tracker.asObject) @@ -66,6 +67,8 @@ class SentryFramesTrackingIntegrationTests: XCTestCase { func testZeroTracesSampleRate_DoesNotMeasureFrames() { let options = fixture.options options.tracesSampleRate = 0.0 + options.appHangTimeoutInterval = 0.0 + options.enableWatchdogTerminationTracking = false sut.install(with: options) XCTAssertNil(Dynamic(sut).tracker.asObject) @@ -75,6 +78,8 @@ class SentryFramesTrackingIntegrationTests: XCTestCase { let options = fixture.options options.tracesSampleRate = 0.1 options.enableAutoPerformanceTracing = false + options.enableAppHangTracking = false + options.enableWatchdogTerminationTracking = false sut.install(with: options) XCTAssertNil(Dynamic(sut).tracker.asObject) @@ -100,14 +105,5 @@ class SentryFramesTrackingIntegrationTests: XCTestCase { XCTAssertNil(fixture.displayLink.target) XCTAssertNil(fixture.displayLink.selector) } - - func test_FramesTracking_Disabled() { - let options = Options() - options.enableAutoPerformanceTracing = false - - let result = fixture.sut.install(with: options) - - XCTAssertFalse(result) - } } #endif diff --git a/Tests/SentryTests/SentryOptionsTest.m b/Tests/SentryTests/SentryOptionsTest.m index c176532403c..7686135be6c 100644 --- a/Tests/SentryTests/SentryOptionsTest.m +++ b/Tests/SentryTests/SentryOptionsTest.m @@ -1486,17 +1486,17 @@ - (void)testSpotlightUrl } #if SENTRY_HAS_UIKIT -- (void)testIsAppHangTrackingV2Disabled_WhenOptionDisabled +- (void)testIsAppHangTrackingDisabled_WhenOptionDisabled { SentryOptions *options = [self getValidOptions:@{ @"appHangTimeoutInterval" : @0 }]; - XCTAssertTrue(options.isAppHangTrackingV2Disabled); + XCTAssertTrue(options.isAppHangTrackingDisabled); } -- (void)testIsAppHangTrackingV2Disabled_WhenOnlyAppHangTimeoutIntervalZero +- (void)testIsAppHangTrackingDisabled_WhenOnlyAppHangTimeoutIntervalZero { SentryOptions *options = [self getValidOptions:@{ @"enableAppHangTracking" : @YES, @"appHangTimeoutInterval" : @0 }]; - XCTAssertTrue(options.isAppHangTrackingV2Disabled); + XCTAssertTrue(options.isAppHangTrackingDisabled); } #endif // SENTRY_HAS_UIKIT From eb2d2dbca9d5c50906de367e9ad64ed33492b0f3 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Mon, 20 Oct 2025 11:15:56 +0200 Subject: [PATCH 06/12] fix enabled features buider tests --- .../Helper/SentryEnabledFeaturesBuilderTests.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift b/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift index 85c573b1d36..9b3848f5e46 100644 --- a/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift +++ b/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift @@ -52,10 +52,6 @@ final class SentryEnabledFeaturesBuilderTests: XCTestCase { XCTAssert(features.contains("preWarmedAppStartTracing")) #endif // canImport(UIKit) #endif // os(iOS) || os(tvOS) - -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - XCTAssert(features.contains("appHangTrackingV2")) -#endif //os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) } func testEnablePersistingTracesWhenCrashing() { From 2b2581c81dae85da02f6d10b754393de54158aa9 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Mon, 20 Oct 2025 11:21:56 +0200 Subject: [PATCH 07/12] update option --- Sources/Sentry/Public/SentryOptions.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 407f7763450..96da6aaf49d 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -639,9 +639,23 @@ typedef void (^SentryProfilingConfigurationBlock)(SentryProfileOptions *_Nonnull /** * When enabled, the SDK tracks when the application stops responding for a specific amount of - * time defined by the @c appHangsTimeoutInterval option. + * time defined by the @c appHangTimeoutInterval option. + * + * On iOS, tvOS and visionOS, the SDK can differentiate between fully-blocking and non-fully + blocking app hangs. + * A fully-blocking app hang is when the main thread is stuck completely, and the app can't render a + * single frame. A non-fully-blocking app hang is when the app appears stuck to the user but can + still + * render a few frames. Fully-blocking app hangs are more actionable because the stacktrace shows + the + * exact blocking location on the main thread. As the main thread isn't completely blocked, + * non-fully-blocking app hangs can have a stacktrace that doesn't highlight the exact blocking + * location. + * + * You can use @c enableReportNonFullyBlockingAppHangs to ignore non-fully-blocking app hangs. + * * @note The default is @c YES - * @note ANR tracking is automatically disabled if a debugger is attached. + * @note App Hang tracking is automatically disabled if a debugger is attached. */ @property (nonatomic, assign) BOOL enableAppHangTracking; From 9c41ff62856a15770f300698bb1fc2a291a07552 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 21 Oct 2025 06:44:02 +0200 Subject: [PATCH 08/12] fix failing test --- .../ANR/SentryANRTrackingIntegrationTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift index a013aab3aac..05110250a95 100644 --- a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift @@ -51,12 +51,12 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { func testWhenNoDebuggerAttached_TrackerInitialized() throws { givenInitializedTracker() - let tracker = try XCTUnwrap(Dynamic(sut).tracker.asAnyObject) + let tracker = try XCTUnwrap(Dynamic(sut).tracker.asAnyObject as? SentryANRTracker) #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - XCTAssertTrue(tracker is SentryANRTrackerV2, "Expected SentryANRTrackerV2, but got \(type(of: tracker))") + XCTAssertTrue(tracker.helper is SentryANRTrackerV2, "Expected SentryANRTrackerV2, but got \(type(of: tracker))") #else - XCTAssertTrue(tracker is SentryANRTrackerV1, "Expected SentryANRTrackerV1 on macOS, but got \(type(of: tracker))") + XCTAssertTrue(tracker.helper is SentryANRTrackerV1, "Expected SentryANRTrackerV1 on macOS, but got \(type(of: tracker))") #endif } From 347420c087a4ea58094dc2ba1e4df5b3abcd1126 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 21 Oct 2025 06:47:30 +0200 Subject: [PATCH 09/12] remove outdated comment --- Sources/Sentry/SentryBaseIntegration.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/Sentry/SentryBaseIntegration.m b/Sources/Sentry/SentryBaseIntegration.m index bcecd63fdea..148c1f61f73 100644 --- a/Sources/Sentry/SentryBaseIntegration.m +++ b/Sources/Sentry/SentryBaseIntegration.m @@ -169,8 +169,6 @@ - (BOOL)shouldBeEnabledWithOptions:(SentryOptions *)options } #endif - // The frames tracker runs when tracing is enabled or AppHangsV2. We have to use an extra option - // for this. if (integrationOptions & kIntegrationOptionStartFramesTracker) { #if SENTRY_HAS_UIKIT From 4d1baacd4ade9c18c52cf6435ed519fa729d5cb8 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 21 Oct 2025 08:49:39 +0200 Subject: [PATCH 10/12] fix tests --- Tests/SentryTests/SentryClientTests.swift | 12 +++++++++--- Tests/SentryTests/SentrySDKTests.swift | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Tests/SentryTests/SentryClientTests.swift b/Tests/SentryTests/SentryClientTests.swift index ce14980e7dc..c9c6156d4f2 100644 --- a/Tests/SentryTests/SentryClientTests.swift +++ b/Tests/SentryTests/SentryClientTests.swift @@ -1711,12 +1711,15 @@ class SentryClientTests: XCTestCase { let eventId = fixture.getSut().capture(message: fixture.messageAsString) eventId.assertIsNotEmpty() - + var expectedIntegrations = ["AutoBreadcrumbTracking", "AutoSessionTracking", "Crash", "NetworkTracking"] if !SentryDependencyContainer.sharedInstance().crashWrapper.isBeingTraced { expectedIntegrations = ["ANRTracking"] + expectedIntegrations } - +#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) + expectedIntegrations.append("FramesTracking") +#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) + let actual = try lastSentEvent() assertArrayEquals( expected: expectedIntegrations, @@ -1755,7 +1758,10 @@ class SentryClientTests: XCTestCase { if !SentryDependencyContainer.sharedInstance().crashWrapper.isBeingTraced { expectedIntegrations = ["ANRTracking"] + expectedIntegrations } - +#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) + expectedIntegrations.append("FramesTracking") +#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) + assertArrayEquals( expected: expectedIntegrations, actual: actual.sdk?["integrations"] as? [String] diff --git a/Tests/SentryTests/SentrySDKTests.swift b/Tests/SentryTests/SentrySDKTests.swift index 17c6d128082..384fb1ff21b 100644 --- a/Tests/SentryTests/SentrySDKTests.swift +++ b/Tests/SentryTests/SentrySDKTests.swift @@ -146,6 +146,9 @@ class SentrySDKTests: XCTestCase { if !SentryDependencyContainer.sharedInstance().crashWrapper.isBeingTraced { expectedIntegrations.append("SentryANRTrackingIntegration") } +#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) + expectedIntegrations.append("SentryFramesTrackingIntegration") +#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) assertIntegrationsInstalled(integrations: expectedIntegrations) } From a40b615dfa00bf3567a62149469fcb1009fa9b70 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 21 Oct 2025 11:13:54 +0200 Subject: [PATCH 11/12] improve assertions for testGoToForeground_SetsIsActive --- .../SentryWatchdogTerminationTrackerTests.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift b/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift index 4ba07a4f48e..84210dc4c83 100644 --- a/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift +++ b/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift @@ -123,13 +123,16 @@ class SentryWatchdogTerminationTrackerTests: NotificationCenterTestCase { sut.start() goToForeground() - - XCTAssertTrue(fixture.fileManager.readAppState()?.isActive ?? false) - + + let appState1 = try XCTUnwrap(fixture.fileManager.readAppState()) + XCTAssertTrue(appState1.isActive, "Expected appSate to be active after going to foreground.") + goToBackground() - - XCTAssertFalse(fixture.fileManager.readAppState()?.isActive ?? true) - XCTAssertEqual(3, fixture.dispatchQueue.dispatchAsyncCalled) + + let appState2 = try XCTUnwrap(fixture.fileManager.readAppState()) + XCTAssertFalse(appState2.isActive, "Expected appSate to be inactive after going to background.") + + XCTAssertEqual(fixture.dispatchQueue.dispatchAsyncCalled, 3) } func testGoToForeground_WhenAppStateNil_NothingIsStored() { From f222a223ea05918068ceb3ccb781b88c177cb95a Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 21 Oct 2025 13:45:05 +0200 Subject: [PATCH 12/12] fix test --- .../SentryWatchdogTerminationTrackerTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift b/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift index 84210dc4c83..ce4cf0f7253 100644 --- a/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift +++ b/Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationTrackerTests.swift @@ -132,7 +132,7 @@ class SentryWatchdogTerminationTrackerTests: NotificationCenterTestCase { let appState2 = try XCTUnwrap(fixture.fileManager.readAppState()) XCTAssertFalse(appState2.isActive, "Expected appSate to be inactive after going to background.") - XCTAssertEqual(fixture.dispatchQueue.dispatchAsyncCalled, 3) + XCTAssertGreaterThanOrEqual(fixture.dispatchQueue.dispatchAsyncCalled, 3, "Expected at least 3 dispatchAsync calls (start, foreground, background) to ensure we don't run reading the app state on the calling thread. ") } func testGoToForeground_WhenAppStateNil_NothingIsStored() {