diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bc28c7d5e..d8d6640e8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,11 @@ This version adds a dependency on Swift. ### Fixes -- Errors shortly after SentrySDK.init now affect the session (#2430) +- Errors shortly after `SentrySDK.init` now affect the session (#2430) - Use the same default environment for events and sessions (#2447) +- Increase `SentryCrashMAX_STRINGBUFFERSIZE` to reduce the instances where we're dropping a crash due to size limit (#2465) +- `SentryAppStateManager` correctly unsubscribes from `NSNotificationCenter` when closing the SDK (#2460) +- The SDK no longer reports an OOM when a crash happens after closing the SDK (#2468) ### Breaking Changes @@ -42,6 +45,7 @@ This version adds a dependency on Swift. - Rename `SentryOptions.enablePreWarmedAppStartTracking` to `enablePreWarmedAppStartTracing` - Rename `SentryOptions.enableFileIOTracking` to `enableFileIOTracing` - Rename `SentryOptions.enableCoreDataTracking` to `enableCoreDataTracing` +- SentrySDK.close calls flush, which is a blocking call (#2453) ## 7.31.3 diff --git a/Package.swift b/Package.swift index b9e1d96e38..361dc3cf3a 100644 --- a/Package.swift +++ b/Package.swift @@ -27,6 +27,7 @@ let package = Package( cxxSettings: [ .define("GCC_ENABLE_CPP_EXCEPTIONS", to: "YES"), .headerSearchPath("Sentry/include"), + .headerSearchPath("Sentry/include/HybridPublic"), .headerSearchPath("Sentry/Public"), .headerSearchPath("SentryCrash/Installations"), .headerSearchPath("SentryCrash/Recording"), diff --git a/Samples/iOS-Swift/iOS-Swift/Base.lproj/Main.storyboard b/Samples/iOS-Swift/iOS-Swift/Base.lproj/Main.storyboard index 029585c65a..f835a85963 100644 --- a/Samples/iOS-Swift/iOS-Swift/Base.lproj/Main.storyboard +++ b/Samples/iOS-Swift/iOS-Swift/Base.lproj/Main.storyboard @@ -122,31 +122,31 @@ - + + @@ -402,14 +410,14 @@ - + - + diff --git a/Samples/iOS-Swift/iOS-Swift/ViewController.swift b/Samples/iOS-Swift/iOS-Swift/ViewController.swift index b74e9c1d00..2c9f13af7c 100644 --- a/Samples/iOS-Swift/iOS-Swift/ViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ViewController.swift @@ -158,7 +158,15 @@ class ViewController: UIViewController { @IBAction func crash(_ sender: Any) { SentrySDK.crash() } - + + // swiftlint:disable force_unwrapping + @IBAction func unwrapCrash(_ sender: Any) { + let a: String! = nil + let b: String = a! + print(b) + } + // swiftlint:enable force_unwrapping + @IBAction func asyncCrash(_ sender: Any) { DispatchQueue.main.async { self.asyncCrash1() diff --git a/Sentry.podspec b/Sentry.podspec index 7167eead87..2418fece37 100644 --- a/Sentry.podspec +++ b/Sentry.podspec @@ -41,6 +41,6 @@ Pod::Spec.new do |s| "Sources/SentryCrash/**/*.{h,hpp,m,mm,c,cpp}", "Sources/Swift/Sentry.swift" sp.public_header_files = - "Sources/Sentry/Public/*.h", "Sources/Sentry/include/PrivateSentrySDKOnly.h" + "Sources/Sentry/Public/*.h", "Sources/Sentry/include/HybridPublic/*.h" end end diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 36b53438c1..1bb1b09f0e 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -79,7 +79,7 @@ 15360CF02433A16D00112302 /* SentryInstallation.h in Headers */ = {isa = PBXBuildFile; fileRef = 15360CEF2433A16D00112302 /* SentryInstallation.h */; }; 15360CF52433C59B00112302 /* SentryInstallationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 15360CF22433C59500112302 /* SentryInstallationTests.m */; }; 15D0AC882459EE4D006541C2 /* SentryNSURLRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15D0AC872459EE4D006541C2 /* SentryNSURLRequestTests.swift */; }; - 15E0A8E1240C41CE00F044E3 /* SentryEnvelope.h in Headers */ = {isa = PBXBuildFile; fileRef = 15E0A8E0240C41CE00F044E3 /* SentryEnvelope.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 15E0A8E1240C41CE00F044E3 /* SentryEnvelope.h in Headers */ = {isa = PBXBuildFile; fileRef = 15E0A8E0240C41CE00F044E3 /* SentryEnvelope.h */; settings = {ATTRIBUTES = (Private, ); }; }; 15E0A8E5240C457D00F044E3 /* SentryEnvelope.m in Sources */ = {isa = PBXBuildFile; fileRef = 15E0A8E4240C457D00F044E3 /* SentryEnvelope.m */; }; 15E0A8EA240F2C9000F044E3 /* SentrySerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 15E0A8E9240F2C8F00F044E3 /* SentrySerialization.h */; }; 15E0A8ED240F2CB000F044E3 /* SentrySerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 15E0A8EC240F2CB000F044E3 /* SentrySerialization.m */; }; @@ -384,7 +384,7 @@ 7B77BE3727EC8460003C9020 /* SentryDiscardReasonMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B77BE3627EC8460003C9020 /* SentryDiscardReasonMapper.m */; }; 7B7A30C624B48321005A4C6E /* SentryCrashWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B7A30C524B48321005A4C6E /* SentryCrashWrapper.h */; }; 7B7A30C824B48389005A4C6E /* SentryCrashWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B7A30C724B48389005A4C6E /* SentryCrashWrapper.m */; }; - 7B7A599526B692540060A676 /* SentryScreenFrames.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B7A599426B692540060A676 /* SentryScreenFrames.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7B7A599526B692540060A676 /* SentryScreenFrames.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B7A599426B692540060A676 /* SentryScreenFrames.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7B7A599726B692F00060A676 /* SentryScreenFrames.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B7A599626B692F00060A676 /* SentryScreenFrames.m */; }; 7B7D872C2486480B00D2ECFF /* SentryStacktraceBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B7D872B2486480B00D2ECFF /* SentryStacktraceBuilder.h */; }; 7B7D872E2486482600D2ECFF /* SentryStacktraceBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B7D872D2486482600D2ECFF /* SentryStacktraceBuilder.m */; }; @@ -501,7 +501,7 @@ 7BC852332458802C005A70F0 /* SentryDataCategoryMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BC852322458802C005A70F0 /* SentryDataCategoryMapper.h */; }; 7BC85235245880AE005A70F0 /* SentryDataCategoryMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC85234245880AE005A70F0 /* SentryDataCategoryMapper.m */; }; 7BC8523724588115005A70F0 /* SentryDataCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BC8523624588115005A70F0 /* SentryDataCategory.h */; }; - 7BC852392458830A005A70F0 /* SentryEnvelopeItemType.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BC852382458830A005A70F0 /* SentryEnvelopeItemType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7BC852392458830A005A70F0 /* SentryEnvelopeItemType.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BC852382458830A005A70F0 /* SentryEnvelopeItemType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7BC8523B2458849E005A70F0 /* SentryDataCategoryMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC8523A2458849E005A70F0 /* SentryDataCategoryMapperTests.swift */; }; 7BC9A20028F41016001E7C4C /* SentryMeasurementValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BC9A1FF28F41016001E7C4C /* SentryMeasurementValue.h */; }; 7BC9A20228F41350001E7C4C /* SentryMeasurementUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BC9A20128F41350001E7C4C /* SentryMeasurementUnit.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -529,7 +529,7 @@ 7BD86EC7264A641D005439DB /* SentrySysctl.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD86EC6264A641D005439DB /* SentrySysctl.m */; }; 7BD86ECB264A6DB5005439DB /* TestSysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD86ECA264A6DB5005439DB /* TestSysctl.swift */; }; 7BD86ECD264A78A6005439DB /* SentryAppStartTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD86ECC264A78A6005439DB /* SentryAppStartTrackerTests.swift */; }; - 7BD86ECF264A7C77005439DB /* SentryAppStartMeasurement.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD86ECE264A7C77005439DB /* SentryAppStartMeasurement.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7BD86ECF264A7C77005439DB /* SentryAppStartMeasurement.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD86ECE264A7C77005439DB /* SentryAppStartMeasurement.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7BD86ED1264A7CF6005439DB /* SentryAppStartMeasurement.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD86ED0264A7CF6005439DB /* SentryAppStartMeasurement.m */; }; 7BDB03B7251364F800BAE198 /* SentryDispatchQueueWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BDB03B6251364F800BAE198 /* SentryDispatchQueueWrapper.h */; }; 7BDB03BB2513652900BAE198 /* SentryDispatchQueueWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB03BA2513652900BAE198 /* SentryDispatchQueueWrapper.m */; }; @@ -722,6 +722,7 @@ D8B76B062808066D000A58C4 /* SentryScreenshotIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B76B042808060E000A58C4 /* SentryScreenshotIntegrationTests.swift */; }; D8B76B0828081461000A58C4 /* TestSentryScreenShot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B76B0728081461000A58C4 /* TestSentryScreenShot.swift */; }; D8BBD32728FD9FC00011F850 /* SentrySwift.h in Headers */ = {isa = PBXBuildFile; fileRef = D8BBD32628FD9FBF0011F850 /* SentrySwift.h */; }; + D8BD2E6829361A0F00D96C6A /* PrivatesHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = D8BD2E67293619F600D96C6A /* PrivatesHeader.h */; settings = {ATTRIBUTES = (Private, ); }; }; D8C67E9B28000E24007E326E /* SentryUIApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = D8C67E9928000E23007E326E /* SentryUIApplication.h */; }; D8C67E9C28000E24007E326E /* SentryScreenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = D8C67E9A28000E23007E326E /* SentryScreenshot.h */; }; D8CE69BC277E39C700C6EC5C /* SentryFileIOTrackingIntegrationObjCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D8CE69BB277E39C700C6EC5C /* SentryFileIOTrackingIntegrationObjCTests.m */; }; @@ -828,7 +829,7 @@ 15360CEF2433A16D00112302 /* SentryInstallation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryInstallation.h; path = include/SentryInstallation.h; sourceTree = ""; }; 15360CF22433C59500112302 /* SentryInstallationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryInstallationTests.m; sourceTree = ""; }; 15D0AC872459EE4D006541C2 /* SentryNSURLRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSURLRequestTests.swift; sourceTree = ""; }; - 15E0A8E0240C41CE00F044E3 /* SentryEnvelope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryEnvelope.h; path = Public/SentryEnvelope.h; sourceTree = ""; }; + 15E0A8E0240C41CE00F044E3 /* SentryEnvelope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryEnvelope.h; path = include/HybridPublic/SentryEnvelope.h; sourceTree = ""; }; 15E0A8E4240C457D00F044E3 /* SentryEnvelope.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryEnvelope.m; sourceTree = ""; }; 15E0A8E9240F2C8F00F044E3 /* SentrySerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentrySerialization.h; path = include/SentrySerialization.h; sourceTree = ""; }; 15E0A8EC240F2CB000F044E3 /* SentrySerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentrySerialization.m; sourceTree = ""; }; @@ -1154,7 +1155,7 @@ 7B7A30C524B48321005A4C6E /* SentryCrashWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryCrashWrapper.h; path = include/SentryCrashWrapper.h; sourceTree = ""; }; 7B7A30C724B48389005A4C6E /* SentryCrashWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashWrapper.m; sourceTree = ""; }; 7B7A30C924B48523005A4C6E /* SentryHub+TestInit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryHub+TestInit.h"; sourceTree = ""; }; - 7B7A599426B692540060A676 /* SentryScreenFrames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryScreenFrames.h; path = Public/SentryScreenFrames.h; sourceTree = ""; }; + 7B7A599426B692540060A676 /* SentryScreenFrames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryScreenFrames.h; path = include/HybridPublic/SentryScreenFrames.h; sourceTree = ""; }; 7B7A599626B692F00060A676 /* SentryScreenFrames.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryScreenFrames.m; sourceTree = ""; }; 7B7D872B2486480B00D2ECFF /* SentryStacktraceBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryStacktraceBuilder.h; path = include/SentryStacktraceBuilder.h; sourceTree = ""; }; 7B7D872D2486482600D2ECFF /* SentryStacktraceBuilder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryStacktraceBuilder.m; sourceTree = ""; }; @@ -1275,7 +1276,7 @@ 7BC852322458802C005A70F0 /* SentryDataCategoryMapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryDataCategoryMapper.h; path = include/SentryDataCategoryMapper.h; sourceTree = ""; }; 7BC85234245880AE005A70F0 /* SentryDataCategoryMapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryDataCategoryMapper.m; sourceTree = ""; }; 7BC8523624588115005A70F0 /* SentryDataCategory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryDataCategory.h; path = include/SentryDataCategory.h; sourceTree = ""; }; - 7BC852382458830A005A70F0 /* SentryEnvelopeItemType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryEnvelopeItemType.h; path = Public/SentryEnvelopeItemType.h; sourceTree = ""; }; + 7BC852382458830A005A70F0 /* SentryEnvelopeItemType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryEnvelopeItemType.h; path = include/HybridPublic/SentryEnvelopeItemType.h; sourceTree = ""; }; 7BC8523A2458849E005A70F0 /* SentryDataCategoryMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryDataCategoryMapperTests.swift; sourceTree = ""; }; 7BC9A1FF28F41016001E7C4C /* SentryMeasurementValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryMeasurementValue.h; path = include/SentryMeasurementValue.h; sourceTree = ""; }; 7BC9A20128F41350001E7C4C /* SentryMeasurementUnit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryMeasurementUnit.h; path = Public/SentryMeasurementUnit.h; sourceTree = ""; }; @@ -1305,7 +1306,7 @@ 7BD86EC6264A641D005439DB /* SentrySysctl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySysctl.m; sourceTree = ""; }; 7BD86ECA264A6DB5005439DB /* TestSysctl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSysctl.swift; sourceTree = ""; }; 7BD86ECC264A78A6005439DB /* SentryAppStartTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryAppStartTrackerTests.swift; sourceTree = ""; }; - 7BD86ECE264A7C77005439DB /* SentryAppStartMeasurement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryAppStartMeasurement.h; path = Public/SentryAppStartMeasurement.h; sourceTree = ""; }; + 7BD86ECE264A7C77005439DB /* SentryAppStartMeasurement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryAppStartMeasurement.h; path = include/HybridPublic/SentryAppStartMeasurement.h; sourceTree = ""; }; 7BD86ED0264A7CF6005439DB /* SentryAppStartMeasurement.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryAppStartMeasurement.m; sourceTree = ""; }; 7BDB03B6251364F800BAE198 /* SentryDispatchQueueWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryDispatchQueueWrapper.h; path = include/SentryDispatchQueueWrapper.h; sourceTree = ""; }; 7BDB03BA2513652900BAE198 /* SentryDispatchQueueWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryDispatchQueueWrapper.m; sourceTree = ""; }; @@ -1493,7 +1494,7 @@ D808FB90281BF6E9009A2A33 /* SentryUIEventTrackingIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUIEventTrackingIntegrationTests.swift; sourceTree = ""; }; D8137D52272B53070082656C /* TestSentrySpan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestSentrySpan.h; sourceTree = ""; }; D8137D53272B53070082656C /* TestSentrySpan.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestSentrySpan.m; sourceTree = ""; }; - D81A346B291AECC7005A27A9 /* PrivateSentrySDKOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivateSentrySDKOnly.h; path = include/PrivateSentrySDKOnly.h; sourceTree = ""; }; + D81A346B291AECC7005A27A9 /* PrivateSentrySDKOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivateSentrySDKOnly.h; path = include/HybridPublic/PrivateSentrySDKOnly.h; sourceTree = ""; }; D81A3488291D0AC0005A27A9 /* SentryPrivate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SentryPrivate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D81A349B291D0C0B005A27A9 /* Sentry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sentry.swift; sourceTree = ""; }; D81A349F291D5568005A27A9 /* SentryPrivate.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = SentryPrivate.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; @@ -1540,6 +1541,7 @@ D8B76B0728081461000A58C4 /* TestSentryScreenShot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentryScreenShot.swift; sourceTree = ""; }; D8BBD32628FD9FBF0011F850 /* SentrySwift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentrySwift.h; path = include/SentrySwift.h; sourceTree = ""; }; D8BD2E27292D1F7300D96C6A /* SDK.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SDK.xcconfig; sourceTree = ""; }; + D8BD2E67293619F600D96C6A /* PrivatesHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PrivatesHeader.h; path = include/HybridPublic/PrivatesHeader.h; sourceTree = ""; }; D8C67E9928000E23007E326E /* SentryUIApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryUIApplication.h; path = include/SentryUIApplication.h; sourceTree = ""; }; D8C67E9A28000E23007E326E /* SentryScreenshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryScreenshot.h; path = include/SentryScreenshot.h; sourceTree = ""; }; D8CE69BB277E39C700C6EC5C /* SentryFileIOTrackingIntegrationObjCTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryFileIOTrackingIntegrationObjCTests.m; sourceTree = ""; }; @@ -1864,6 +1866,7 @@ isa = PBXGroup; children = ( 63AA76951EB9C1C200D153DE /* SentryDefines.h */, + D8BD2E67293619F600D96C6A /* PrivatesHeader.h */, 63AA769B1EB9C57A00D153DE /* SentryError.h */, 63AA769C1EB9C57A00D153DE /* SentryError.m */, 7B42C47F27E08F33009B58C2 /* SentryDependencyContainer.h */, @@ -3167,6 +3170,7 @@ 03F84D2027DD414C008FE43F /* SentryStackBounds.hpp in Headers */, 8E5D38E3261D4B57000D363D /* SentryPerformanceTrackingIntegration.h in Headers */, 63FE70F920DA4C1000CDBAE8 /* SentryCrashMonitor.h in Headers */, + D8BD2E6829361A0F00D96C6A /* PrivatesHeader.h in Headers */, 7B98D7CB25FB64EC00C5A389 /* SentryOutOfMemoryTrackingIntegration.h in Headers */, 63FE710920DA4C1000CDBAE8 /* SentryCrashFileUtils.h in Headers */, 03F84D1F27DD414C008FE43F /* SentryAsyncSafeLogging.h in Headers */, diff --git a/Sources/Sentry/Public/Sentry.h b/Sources/Sentry/Public/Sentry.h index 0edc354719..349e0e51ab 100644 --- a/Sources/Sentry/Public/Sentry.h +++ b/Sources/Sentry/Public/Sentry.h @@ -6,7 +6,6 @@ FOUNDATION_EXPORT double SentryVersionNumber; //! Project version string for Sentry. FOUNDATION_EXPORT const unsigned char SentryVersionString[]; -#import "SentryAppStartMeasurement.h" #import "SentryAttachment.h" #import "SentryBreadcrumb.h" #import "SentryClient.h" @@ -15,8 +14,6 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; #import "SentryDebugMeta.h" #import "SentryDefines.h" #import "SentryDsn.h" -#import "SentryEnvelope.h" -#import "SentryEnvelopeItemType.h" #import "SentryError.h" #import "SentryEvent.h" #import "SentryException.h" @@ -37,6 +34,7 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; #import "SentrySamplingContext.h" #import "SentryScope.h" #import "SentryScreenFrames.h" +#import "SentrySdkInfo.h" #import "SentrySerializable.h" #import "SentrySpanContext.h" #import "SentrySpanId.h" diff --git a/Sources/Sentry/Public/SentryClient.h b/Sources/Sentry/Public/SentryClient.h index ba2042b1d5..399e348b1e 100644 --- a/Sources/Sentry/Public/SentryClient.h +++ b/Sources/Sentry/Public/SentryClient.h @@ -8,6 +8,8 @@ NS_ASSUME_NONNULL_BEGIN @interface SentryClient : NSObject SENTRY_NO_INIT +@property (nonatomic, assign, readonly) BOOL isEnabled; + @property (nonatomic, strong) SentryOptions *options; /** @@ -119,6 +121,11 @@ SENTRY_NO_INIT */ - (void)flush:(NSTimeInterval)timeout NS_SWIFT_NAME(flush(timeout:)); +/** + * Disables the client and calls flush with ``SentryOptions/shutdownTimeInterval``. + */ +- (void)close; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/Public/SentryHub.h b/Sources/Sentry/Public/SentryHub.h index 9a5bb369b9..88609c6f4a 100644 --- a/Sources/Sentry/Public/SentryHub.h +++ b/Sources/Sentry/Public/SentryHub.h @@ -268,6 +268,11 @@ SENTRY_NO_INIT */ - (void)flush:(NSTimeInterval)timeout NS_SWIFT_NAME(flush(timeout:)); +/** + * Calls flush with ``SentryOptions/shutdownTimeInterval``. + */ +- (void)close; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 926cfd3e5f..ff8d85a953 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -58,6 +58,11 @@ NS_SWIFT_NAME(Options) */ @property (nonatomic, assign) BOOL enabled; +/** + * Controls the flush duration when calling ``SentrySDK/close``. + */ +@property (nonatomic, assign) NSTimeInterval shutdownTimeInterval; + /** * When enabled, the SDK sends crashes to Sentry. Default value is YES. */ diff --git a/Sources/Sentry/Public/SentrySDK.h b/Sources/Sentry/Public/SentrySDK.h index 595bd6cea1..6ceee4f6c2 100644 --- a/Sources/Sentry/Public/SentrySDK.h +++ b/Sources/Sentry/Public/SentrySDK.h @@ -311,7 +311,8 @@ SENTRY_NO_INIT + (void)flush:(NSTimeInterval)timeout NS_SWIFT_NAME(flush(timeout:)); /** - * Closes the SDK and uninstalls all the integrations. + * Closes the SDK, uninstalls all the integrations, and calls flush with + * ``SentryOptions/shutdownTimeInterval``. */ + (void)close; diff --git a/Sources/Sentry/SentryAppState.m b/Sources/Sentry/SentryAppState.m index 9c339e9a3b..cef2a8e709 100644 --- a/Sources/Sentry/SentryAppState.m +++ b/Sources/Sentry/SentryAppState.m @@ -25,6 +25,7 @@ - (instancetype)initWithReleaseName:(NSString *)releaseName _isActive = NO; _wasTerminated = NO; _isANROngoing = NO; + _isSDKRunning = YES; } return self; } @@ -89,6 +90,15 @@ - (nullable instancetype)initWithJSONObject:(NSDictionary *)jsonObject } else { _isANROngoing = [isANROngoing boolValue]; } + + id isSDKRunning = [jsonObject valueForKey:@"is_sdk_running"]; + if (isSDKRunning == nil || ![isSDKRunning isKindOfClass:[NSNumber class]]) { + // This property was added later so instead of returning nil, + // we're setting it to the default value. + _isSDKRunning = YES; + } else { + _isSDKRunning = [isSDKRunning boolValue]; + } } return self; } @@ -106,6 +116,7 @@ - (nullable instancetype)initWithJSONObject:(NSDictionary *)jsonObject [data setValue:@(self.isActive) forKey:@"is_active"]; [data setValue:@(self.wasTerminated) forKey:@"was_terminated"]; [data setValue:@(self.isANROngoing) forKey:@"is_anr_ongoing"]; + [data setValue:@(self.isSDKRunning) forKey:@"is_sdk_running"]; return data; } diff --git a/Sources/Sentry/SentryAppStateManager.m b/Sources/Sentry/SentryAppStateManager.m index 0302320f5e..fb187df795 100644 --- a/Sources/Sentry/SentryAppStateManager.m +++ b/Sources/Sentry/SentryAppStateManager.m @@ -7,6 +7,7 @@ #import #import #import +#import #import #if SENTRY_HAS_UIKIT @@ -24,6 +25,7 @@ @property (nonatomic, strong) id currentDate; @property (nonatomic, strong) SentrySysctl *sysctl; @property (nonatomic, strong) SentryDispatchQueueWrapper *dispatchQueue; +@property (nonatomic, strong) SentryNSNotificationCenterWrapper *notificationCenterWrapper; @property (nonatomic) NSInteger startCount; @end @@ -36,6 +38,7 @@ - (instancetype)initWithOptions:(SentryOptions *)options currentDateProvider:(id)currentDateProvider sysctl:(SentrySysctl *)sysctl dispatchQueueWrapper:(SentryDispatchQueueWrapper *)dispatchQueueWrapper + notificationCenterWrapper:(SentryNSNotificationCenterWrapper *)notificationCenterWrapper { if (self = [super init]) { self.options = options; @@ -44,6 +47,7 @@ - (instancetype)initWithOptions:(SentryOptions *)options self.currentDate = currentDateProvider; self.sysctl = sysctl; self.dispatchQueue = dispatchQueueWrapper; + self.notificationCenterWrapper = notificationCenterWrapper; self.startCount = 0; } return self; @@ -54,29 +58,24 @@ - (instancetype)initWithOptions:(SentryOptions *)options - (void)start { if (self.startCount == 0) { - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper addObserver:self selector:@selector(didBecomeActive) - name:SentryNSNotificationCenterWrapper.didBecomeActiveNotificationName - object:nil]; + name:SentryNSNotificationCenterWrapper.didBecomeActiveNotificationName]; - [NSNotificationCenter.defaultCenter - addObserver:self - selector:@selector(didBecomeActive) - name:SentryHybridSdkDidBecomeActiveNotificationName - object:nil]; + [self.notificationCenterWrapper addObserver:self + selector:@selector(didBecomeActive) + name:SentryHybridSdkDidBecomeActiveNotificationName]; - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper addObserver:self selector:@selector(willResignActive) - name:SentryNSNotificationCenterWrapper.willResignActiveNotificationName - object:nil]; + name:SentryNSNotificationCenterWrapper.willResignActiveNotificationName]; - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper addObserver:self selector:@selector(willTerminate) - name:SentryNSNotificationCenterWrapper.willTerminateNotificationName - object:nil]; + name:SentryNSNotificationCenterWrapper.willTerminateNotificationName]; [self storeCurrentAppState]; } @@ -85,35 +84,44 @@ - (void)start } - (void)stop +{ + [self stopWithForce:NO]; +} + +// forceStop is YES when the SDK gets closed +- (void)stopWithForce:(BOOL)forceStop { if (self.startCount <= 0) { return; } - self.startCount -= 1; + if (forceStop) { + [self + updateAppStateInBackground:^(SentryAppState *appState) { appState.isSDKRunning = NO; }]; + + self.startCount = 0; + } else { + self.startCount -= 1; + } if (self.startCount == 0) { // Remove the observers with the most specific detail possible, see // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper removeObserver:self - name:SentryNSNotificationCenterWrapper.didBecomeActiveNotificationName - object:nil]; + name:SentryNSNotificationCenterWrapper.didBecomeActiveNotificationName]; - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper removeObserver:self - name:SentryHybridSdkDidBecomeActiveNotificationName - object:nil]; + name:SentryHybridSdkDidBecomeActiveNotificationName]; - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper removeObserver:self - name:SentryNSNotificationCenterWrapper.willResignActiveNotificationName - object:nil]; + name:SentryNSNotificationCenterWrapper.willResignActiveNotificationName]; - [NSNotificationCenter.defaultCenter + [self.notificationCenterWrapper removeObserver:self - name:SentryNSNotificationCenterWrapper.willTerminateNotificationName - object:nil]; + name:SentryNSNotificationCenterWrapper.willTerminateNotificationName]; } } @@ -121,7 +129,7 @@ - (void)dealloc { // In dealloc it's safe to unsubscribe for all, see // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver - [NSNotificationCenter.defaultCenter removeObserver:self]; + [self.notificationCenterWrapper removeObserver:self]; } /** diff --git a/Sources/Sentry/SentryClient.m b/Sources/Sentry/SentryClient.m index 87427ab9d3..8e0b30019f 100644 --- a/Sources/Sentry/SentryClient.m +++ b/Sources/Sentry/SentryClient.m @@ -162,6 +162,7 @@ - (instancetype)initWithOptions:(SentryOptions *)options timezone:(NSTimeZone *)timezone { if (self = [super init]) { + _isEnabled = YES; self.options = options; self.transportAdapter = transportAdapter; self.fileManager = fileManager; @@ -501,6 +502,12 @@ - (void)flush:(NSTimeInterval)timeout [self.transportAdapter flush:timeout]; } +- (void)close +{ + _isEnabled = NO; + [self flush:self.options.shutdownTimeInterval]; +} + - (SentryEvent *_Nullable)prepareEvent:(SentryEvent *)event withScope:(SentryScope *)scope alwaysAttachStacktrace:(BOOL)alwaysAttachStacktrace @@ -632,7 +639,7 @@ - (BOOL)isSampled:(NSNumber *)sampleRate - (BOOL)isDisabled { - return !self.options.enabled || nil == self.options.parsedDsn; + return !_isEnabled || !self.options.enabled || nil == self.options.parsedDsn; } - (void)logDisabledMessage diff --git a/Sources/Sentry/SentryDependencyContainer.m b/Sources/Sentry/SentryDependencyContainer.m index 17df37182b..1cf121063f 100644 --- a/Sources/Sentry/SentryDependencyContainer.m +++ b/Sources/Sentry/SentryDependencyContainer.m @@ -63,12 +63,13 @@ - (SentryAppStateManager *)appStateManager if (_appStateManager == nil) { SentryOptions *options = [[[SentrySDK currentHub] getClient] options]; _appStateManager = [[SentryAppStateManager alloc] - initWithOptions:options - crashWrapper:self.crashWrapper - fileManager:self.fileManager - currentDateProvider:[SentryDefaultCurrentDateProvider sharedInstance] - sysctl:[[SentrySysctl alloc] init] - dispatchQueueWrapper:self.dispatchQueueWrapper]; + initWithOptions:options + crashWrapper:self.crashWrapper + fileManager:self.fileManager + currentDateProvider:[SentryDefaultCurrentDateProvider sharedInstance] + sysctl:[[SentrySysctl alloc] init] + dispatchQueueWrapper:self.dispatchQueueWrapper + notificationCenterWrapper:self.notificationCenterWrapper]; } return _appStateManager; } diff --git a/Sources/Sentry/SentryHub.m b/Sources/Sentry/SentryHub.m index 3b79664304..aa9bd29791 100644 --- a/Sources/Sentry/SentryHub.m +++ b/Sources/Sentry/SentryHub.m @@ -672,6 +672,11 @@ - (void)flush:(NSTimeInterval)timeout } } +- (void)close +{ + [_client close]; +} + @end NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 4596cb6b0f..86c47bad49 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -47,6 +47,7 @@ - (instancetype)init { if (self = [super init]) { self.enabled = YES; + self.shutdownTimeInterval = 2.0; self.enableCrashHandler = YES; self.diagnosticLevel = kSentryLevelDebug; self.debug = NO; diff --git a/Sources/Sentry/SentryOutOfMemoryLogic.m b/Sources/Sentry/SentryOutOfMemoryLogic.m index 95fa5a4c1c..c0265dc965 100644 --- a/Sources/Sentry/SentryOutOfMemoryLogic.m +++ b/Sources/Sentry/SentryOutOfMemoryLogic.m @@ -44,7 +44,7 @@ - (BOOL)isOOM SentryAppState *currentAppState = [self.appStateManager buildCurrentAppState]; // If there is no previous app state, we can't do anything. - if (nil == previousAppState) { + if (previousAppState == nil) { return NO; } @@ -84,6 +84,11 @@ - (BOOL)isOOM return NO; } + // The SDK wasn't running, so *any* crash after the SDK got closed would be seen as OOM. + if (!previousAppState.isSDKRunning) { + return NO; + } + // Was the app in foreground/active ? // If the app was in background we can't reliably tell if it was an OOM or not. if (!previousAppState.isActive) { diff --git a/Sources/Sentry/SentrySDK.m b/Sources/Sentry/SentrySDK.m index 2d036a9bb1..f4568f0b3f 100644 --- a/Sources/Sentry/SentrySDK.m +++ b/Sources/Sentry/SentrySDK.m @@ -1,6 +1,7 @@ #import "SentrySDK.h" #import "PrivateSentrySDKOnly.h" #import "SentryAppStartMeasurement.h" +#import "SentryAppStateManager.h" #import "SentryBreadcrumb.h" #import "SentryClient+Private.h" #import "SentryCrash.h" @@ -403,9 +404,13 @@ + (void)close } [hub removeAllIntegrations]; - // close the client - SentryClient *client = [hub getClient]; - client.options.enabled = NO; +#if SENTRY_HAS_UIKIT + // force the AppStateManager to unsubscribe, see + // https://github.com/getsentry/sentry-cocoa/issues/2455 + [[SentryDependencyContainer sharedInstance].appStateManager stopWithForce:YES]; +#endif + + [hub close]; [hub bindClient:nil]; [SentrySDK setCurrentHub:nil]; diff --git a/Sources/Sentry/include/PrivateSentrySDKOnly.h b/Sources/Sentry/include/HybridPublic/PrivateSentrySDKOnly.h similarity index 91% rename from Sources/Sentry/include/PrivateSentrySDKOnly.h rename to Sources/Sentry/include/HybridPublic/PrivateSentrySDKOnly.h index b4ed92270f..6931448148 100644 --- a/Sources/Sentry/include/PrivateSentrySDKOnly.h +++ b/Sources/Sentry/include/HybridPublic/PrivateSentrySDKOnly.h @@ -1,11 +1,8 @@ -// We need this because if Sentry library is added as a Framework -// the reference should be in the form of . -// Otherwise, the reference is direct. -#if __has_include() -# import -#else -# import "SentryDefines.h" -#endif +#import "PrivatesHeader.h" +#import "SentryAppStartMeasurement.h" +#import "SentryEnvelope.h" +#import "SentryEnvelopeItemType.h" +#import "SentryScreenFrames.h" @class SentryEnvelope, SentryDebugMeta, SentryAppStartMeasurement, SentryScreenFrames, SentryOptions; diff --git a/Sources/Sentry/include/HybridPublic/PrivatesHeader.h b/Sources/Sentry/include/HybridPublic/PrivatesHeader.h new file mode 100644 index 0000000000..05bdfa7be9 --- /dev/null +++ b/Sources/Sentry/include/HybridPublic/PrivatesHeader.h @@ -0,0 +1,14 @@ +// We need this because if Sentry library is added as a Framework +// the reference should be in the form of . +// Otherwise, the reference is direct. +#if __has_include() +# import +#else +# import "SentryDefines.h" +#endif + +#if __has_include() +# import +#else +# import "SentryProfilingConditionals.h" +#endif diff --git a/Sources/Sentry/Public/SentryAppStartMeasurement.h b/Sources/Sentry/include/HybridPublic/SentryAppStartMeasurement.h similarity index 98% rename from Sources/Sentry/Public/SentryAppStartMeasurement.h rename to Sources/Sentry/include/HybridPublic/SentryAppStartMeasurement.h index f908e25b21..729da075e1 100644 --- a/Sources/Sentry/Public/SentryAppStartMeasurement.h +++ b/Sources/Sentry/include/HybridPublic/SentryAppStartMeasurement.h @@ -1,4 +1,4 @@ -#import "SentryDefines.h" +#import "PrivatesHeader.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/Sentry/Public/SentryEnvelope.h b/Sources/Sentry/include/HybridPublic/SentryEnvelope.h similarity index 99% rename from Sources/Sentry/Public/SentryEnvelope.h rename to Sources/Sentry/include/HybridPublic/SentryEnvelope.h index e99f59447d..6f7aef795d 100644 --- a/Sources/Sentry/Public/SentryEnvelope.h +++ b/Sources/Sentry/include/HybridPublic/SentryEnvelope.h @@ -1,7 +1,6 @@ +#import "PrivatesHeader.h" #import -#import "SentryDefines.h" - @class SentryEvent, SentrySession, SentrySdkInfo, SentryId, SentryUserFeedback, SentryAttachment, SentryTransaction, SentryTraceContext, SentryClientReport; diff --git a/Sources/Sentry/Public/SentryEnvelopeItemType.h b/Sources/Sentry/include/HybridPublic/SentryEnvelopeItemType.h similarity index 100% rename from Sources/Sentry/Public/SentryEnvelopeItemType.h rename to Sources/Sentry/include/HybridPublic/SentryEnvelopeItemType.h diff --git a/Sources/Sentry/Public/SentryScreenFrames.h b/Sources/Sentry/include/HybridPublic/SentryScreenFrames.h similarity index 96% rename from Sources/Sentry/Public/SentryScreenFrames.h rename to Sources/Sentry/include/HybridPublic/SentryScreenFrames.h index ec182d69cd..9c64e51dad 100644 --- a/Sources/Sentry/Public/SentryScreenFrames.h +++ b/Sources/Sentry/include/HybridPublic/SentryScreenFrames.h @@ -1,5 +1,4 @@ -#import "SentryDefines.h" -#import "SentryProfilingConditionals.h" +#import "PrivatesHeader.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/Sentry/include/SentryAppState.h b/Sources/Sentry/include/SentryAppState.h index d5e4a2bb32..1d099734fb 100644 --- a/Sources/Sentry/include/SentryAppState.h +++ b/Sources/Sentry/include/SentryAppState.h @@ -42,6 +42,8 @@ SENTRY_NO_INIT @property (nonatomic, assign) BOOL isANROngoing; +@property (nonatomic, assign) BOOL isSDKRunning; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/include/SentryAppStateManager.h b/Sources/Sentry/include/SentryAppStateManager.h index d50ab4ff1a..c1cb0017d1 100644 --- a/Sources/Sentry/include/SentryAppStateManager.h +++ b/Sources/Sentry/include/SentryAppStateManager.h @@ -2,24 +2,28 @@ #import "SentryDefines.h" @class SentryOptions, SentryCrashWrapper, SentryAppState, SentryFileManager, SentrySysctl, - SentryDispatchQueueWrapper; + SentryDispatchQueueWrapper, SentryNSNotificationCenterWrapper; NS_ASSUME_NONNULL_BEGIN @interface SentryAppStateManager : NSObject SENTRY_NO_INIT +@property (nonatomic, readonly) NSInteger startCount; + - (instancetype)initWithOptions:(SentryOptions *)options crashWrapper:(SentryCrashWrapper *)crashWrapper fileManager:(SentryFileManager *)fileManager currentDateProvider:(id)currentDateProvider sysctl:(SentrySysctl *)sysctl - dispatchQueueWrapper:(SentryDispatchQueueWrapper *)dispatchQueueWrapper; + dispatchQueueWrapper:(SentryDispatchQueueWrapper *)dispatchQueueWrapper + notificationCenterWrapper:(SentryNSNotificationCenterWrapper *)notificationCenterWrapper; #if SENTRY_HAS_UIKIT - (void)start; - (void)stop; +- (void)stopWithForce:(BOOL)forceStop; /** * Builds the current app state. diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h index fedb3bf96a..11212e335d 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h @@ -42,7 +42,7 @@ extern "C" { */ #define SentryCrashJSON_SIZE_AUTOMATIC -1 -#define SentryCrashMAX_STRINGBUFFERSIZE 100000 +#define SentryCrashMAX_STRINGBUFFERSIZE 150000 enum { /** Encoding or decoding: Everything completed without error */ diff --git a/Tests/SentryTests/Helper/SentryAppStateManagerTests.swift b/Tests/SentryTests/Helper/SentryAppStateManagerTests.swift index ac98454fa9..62bec16744 100644 --- a/Tests/SentryTests/Helper/SentryAppStateManagerTests.swift +++ b/Tests/SentryTests/Helper/SentryAppStateManagerTests.swift @@ -11,6 +11,7 @@ class SentryAppStateManagerTests: XCTestCase { let fileManager: SentryFileManager let currentDate = TestCurrentDateProvider() let dispatchQueue = TestSentryDispatchQueueWrapper() + let notificationCenterWrapper = TestNSNotificationCenterWrapper() init() { options = Options() @@ -27,7 +28,8 @@ class SentryAppStateManagerTests: XCTestCase { fileManager: fileManager, currentDateProvider: currentDate, sysctl: TestSysctl(), - dispatchQueueWrapper: TestSentryDispatchQueueWrapper() + dispatchQueueWrapper: TestSentryDispatchQueueWrapper(), + notificationCenterWrapper: notificationCenterWrapper ) } } @@ -76,6 +78,34 @@ class SentryAppStateManagerTests: XCTestCase { XCTAssertNotNil(fixture.fileManager.readAppState()) } + func testStopUpdatesAppState() { + sut.start() + + let stateBeforeStop = fixture.fileManager.readAppState() + XCTAssertTrue(stateBeforeStop!.isSDKRunning) + + sut.stop(withForce: true) + + let stateAfterStop = fixture.fileManager.readAppState() + XCTAssertFalse(stateAfterStop!.isSDKRunning) + } + + func testForcedStop() { + XCTAssertNil(fixture.fileManager.readAppState()) + + sut.start() + sut.start() + sut.start() + + sut.stop() + XCTAssertEqual(sut.startCount, 2) + + sut.stop(withForce: true) + XCTAssertEqual(sut.startCount, 0) + + XCTAssertEqual(fixture.notificationCenterWrapper.removeObserverWithNameInvocations.count, 4) + } + func testUpdateAppState() { sut.storeCurrentAppState() diff --git a/Tests/SentryTests/Helper/SentryAppStateTests.swift b/Tests/SentryTests/Helper/SentryAppStateTests.swift index 9bb07cb3ad..2d54d0b568 100644 --- a/Tests/SentryTests/Helper/SentryAppStateTests.swift +++ b/Tests/SentryTests/Helper/SentryAppStateTests.swift @@ -14,6 +14,7 @@ class SentryAppStateTests: XCTestCase { XCTAssertEqual(appState.isActive, actual["is_active"] as? Bool) XCTAssertEqual(appState.wasTerminated, actual["was_terminated"] as? Bool) XCTAssertEqual(appState.isANROngoing, actual["is_anr_ongoing"] as? Bool) + XCTAssertEqual(appState.isSDKRunning, actual["is_sdk_running"] as? Bool) } func testInitWithJSON_AllFields() { @@ -26,7 +27,8 @@ class SentryAppStateTests: XCTestCase { "system_boot_timestamp": (appState.systemBootTimestamp as NSDate).sentry_toIso8601String(), "is_active": appState.isActive, "was_terminated": appState.wasTerminated, - "is_anr_ongoing": appState.isANROngoing + "is_anr_ongoing": appState.isANROngoing, + "is_sdk_running": appState.isSDKRunning ] as [String: Any] let actual = SentryAppState(jsonObject: dict) diff --git a/Tests/SentryTests/Helper/TestNSNotificationCenterWrapper.swift b/Tests/SentryTests/Helper/TestNSNotificationCenterWrapper.swift index 81289540ce..1d9fc0e2f6 100644 --- a/Tests/SentryTests/Helper/TestNSNotificationCenterWrapper.swift +++ b/Tests/SentryTests/Helper/TestNSNotificationCenterWrapper.swift @@ -1,25 +1,20 @@ import Foundation @objc public class TestNSNotificationCenterWrapper: SentryNSNotificationCenterWrapper { - var addObserverInvocations = Invocations<(observer: Any, selector: Selector, name: NSNotification.Name)>() @objc public var addObserverInvocationsCount: Int { return addObserverInvocations.count } - + public override func addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name) { addObserverInvocations.record((observer, aSelector, aName)) } - - var addObserverWithNotificationInvocations = Invocations<(observer: Any, name: NSNotification.Name)>() - @objc public var removeWithNotificationInvocationsCount: Int { - return addObserverWithNotificationInvocations.count - } - + + var removeObserverWithNameInvocations = Invocations<(observer: Any, name: NSNotification.Name)>() public override func removeObserver(_ observer: Any, name aName: NSNotification.Name) { - addObserverWithNotificationInvocations.record((observer, aName)) + removeObserverWithNameInvocations.record((observer, aName)) } - + var removeObserverInvocations = Invocations() public override func removeObserver(_ observer: Any) { removeObserverInvocations.record(observer) diff --git a/Tests/SentryTests/Integrations/OutOfMemory/SentryOutOfMemoryTrackerTests.swift b/Tests/SentryTests/Integrations/OutOfMemory/SentryOutOfMemoryTrackerTests.swift index 05ea929fdf..a6c9d56ee6 100644 --- a/Tests/SentryTests/Integrations/OutOfMemory/SentryOutOfMemoryTrackerTests.swift +++ b/Tests/SentryTests/Integrations/OutOfMemory/SentryOutOfMemoryTrackerTests.swift @@ -36,9 +36,27 @@ class SentryOutOfMemoryTrackerTests: NotificationCenterTestCase { } func getSut(fileManager: SentryFileManager) -> SentryOutOfMemoryTracker { - let appStateManager = SentryAppStateManager(options: options, crashWrapper: crashWrapper, fileManager: fileManager, currentDateProvider: currentDate, sysctl: sysctl, dispatchQueueWrapper: self.dispatchQueue) - let logic = SentryOutOfMemoryLogic(options: options, crashAdapter: crashWrapper, appStateManager: appStateManager) - return SentryOutOfMemoryTracker(options: options, outOfMemoryLogic: logic, appStateManager: appStateManager, dispatchQueueWrapper: dispatchQueue, fileManager: fileManager) + let appStateManager = SentryAppStateManager( + options: options, + crashWrapper: crashWrapper, + fileManager: fileManager, + currentDateProvider: currentDate, + sysctl: sysctl, + dispatchQueueWrapper: self.dispatchQueue, + notificationCenterWrapper: SentryNSNotificationCenterWrapper() + ) + let logic = SentryOutOfMemoryLogic( + options: options, + crashAdapter: crashWrapper, + appStateManager: appStateManager + ) + return SentryOutOfMemoryTracker( + options: options, + outOfMemoryLogic: logic, + appStateManager: appStateManager, + dispatchQueueWrapper: dispatchQueue, + fileManager: fileManager + ) } } @@ -169,7 +187,16 @@ class SentryOutOfMemoryTrackerTests: NotificationCenterTestCase { assertNoOOMSent() } - + + func testSDKWasClosed_NoOOM() { + let appState = SentryAppState(releaseName: TestData.appState.releaseName, osVersion: UIDevice.current.systemVersion, vendorId: TestData.someUUID, isDebugging: false, systemBootTimestamp: fixture.currentDate.date()) + appState.isSDKRunning = false + + givenPreviousAppState(appState: appState) + sut.start() + assertNoOOMSent() + } + func testAppWasInBackground_NoOOM() { sut.start() goToForeground() diff --git a/Tests/SentryTests/Integrations/Performance/AppStartTracking/SentryAppStartTrackerTests.swift b/Tests/SentryTests/Integrations/Performance/AppStartTracking/SentryAppStartTrackerTests.swift index 25cdf277a6..21557232de 100644 --- a/Tests/SentryTests/Integrations/Performance/AppStartTracking/SentryAppStartTrackerTests.swift +++ b/Tests/SentryTests/Integrations/Performance/AppStartTracking/SentryAppStartTrackerTests.swift @@ -29,7 +29,15 @@ class SentryAppStartTrackerTests: NotificationCenterTestCase { fileManager = try! SentryFileManager(options: options, andCurrentDateProvider: currentDate, dispatchQueueWrapper: dispatchQueue) - appStateManager = SentryAppStateManager(options: options, crashWrapper: crashWrapper, fileManager: fileManager, currentDateProvider: currentDate, sysctl: sysctl, dispatchQueueWrapper: dispatchQueue) + appStateManager = SentryAppStateManager( + options: options, + crashWrapper: crashWrapper, + fileManager: fileManager, + currentDateProvider: currentDate, + sysctl: sysctl, + dispatchQueueWrapper: dispatchQueue, + notificationCenterWrapper: SentryNSNotificationCenterWrapper() + ) runtimeInitTimestamp = currentDate.date().addingTimeInterval(0.2) moduleInitializationTimestamp = currentDate.date().addingTimeInterval(0.1) @@ -37,7 +45,13 @@ class SentryAppStartTrackerTests: NotificationCenterTestCase { } var sut: SentryAppStartTracker { - let sut = SentryAppStartTracker(currentDateProvider: currentDate, dispatchQueueWrapper: TestSentryDispatchQueueWrapper(), appStateManager: appStateManager, sysctl: sysctl, enablePreWarmedAppStartTracing: enablePreWarmedAppStartTracing) + let sut = SentryAppStartTracker( + currentDateProvider: currentDate, + dispatchQueueWrapper: TestSentryDispatchQueueWrapper(), + appStateManager: appStateManager, + sysctl: sysctl, + enablePreWarmedAppStartTracing: enablePreWarmedAppStartTracing + ) return sut } } diff --git a/Tests/SentryTests/Integrations/Session/SentrySessionTrackerTests.swift b/Tests/SentryTests/Integrations/Session/SentrySessionTrackerTests.swift index ad4060b447..c9b42f0777 100644 --- a/Tests/SentryTests/Integrations/Session/SentrySessionTrackerTests.swift +++ b/Tests/SentryTests/Integrations/Session/SentrySessionTrackerTests.swift @@ -353,7 +353,7 @@ class SentrySessionTrackerTests: XCTestCase { func testStop_RemovesObservers() { sut.stop() - let invocations = fixture.notificationCenter.addObserverWithNotificationInvocations + let invocations = fixture.notificationCenter.removeObserverWithNameInvocations let notificationNames = invocations.invocations.map { $0.name } assertNotificationNames(notificationNames) diff --git a/Tests/SentryTests/SentryClientTests.swift b/Tests/SentryTests/SentryClientTests.swift index a8565d305f..86236d71db 100644 --- a/Tests/SentryTests/SentryClientTests.swift +++ b/Tests/SentryTests/SentryClientTests.swift @@ -134,6 +134,10 @@ class SentryClientTest: XCTestCase { clearTestState() } + func testClientIsEnabled() { + XCTAssertTrue(fixture.getSut().isEnabled) + } + func testCaptureMessage() { let eventId = fixture.getSut().capture(message: fixture.messageAsString) diff --git a/Tests/SentryTests/SentryCrash/SentryCrashInstallationTests.m b/Tests/SentryTests/SentryCrash/SentryCrashInstallationTests.m index 31916f58df..df94165d16 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashInstallationTests.m +++ b/Tests/SentryTests/SentryCrash/SentryCrashInstallationTests.m @@ -62,7 +62,7 @@ - (void)testUninstall_CallsRemoveObservers [installation uninstall]; #if SentryCrashCRASH_HAS_UIAPPLICATION - XCTAssertEqual(5, self.notificationCenter.removeWithNotificationInvocationsCount); + XCTAssertEqual(5, self.notificationCenter.removeObserverWithNameInvocations.count); #endif } @@ -95,7 +95,7 @@ - (void)testUninstall_Install crashHandlerDataAfterInstall:crashHandlerDataAfterInstall]; #if SentryCrashCRASH_HAS_UIAPPLICATION - XCTAssertEqual(55, self.notificationCenter.removeWithNotificationInvocationsCount); + XCTAssertEqual(55, self.notificationCenter.removeObserverWithNameInvocations.count); #endif } diff --git a/Tests/SentryTests/SentryOptionsTest.m b/Tests/SentryTests/SentryOptionsTest.m index a24e5fba9f..380c80063e 100644 --- a/Tests/SentryTests/SentryOptionsTest.m +++ b/Tests/SentryTests/SentryOptionsTest.m @@ -78,6 +78,7 @@ - (void)testEmptyConstructorSetsDefaultValues - (void)assertDefaultValues:(SentryOptions *)options { XCTAssertEqual(YES, options.enabled); + XCTAssertEqual(2.0, options.shutdownTimeInterval); XCTAssertEqual(NO, options.debug); XCTAssertEqual(kSentryLevelDebug, options.diagnosticLevel); XCTAssertEqual(options.environment, kSentryDefaultEnvironment); diff --git a/Tests/SentryTests/SentrySDKTests.swift b/Tests/SentryTests/SentrySDKTests.swift index 2012647357..e745b40ab6 100644 --- a/Tests/SentryTests/SentrySDKTests.swift +++ b/Tests/SentryTests/SentrySDKTests.swift @@ -492,6 +492,67 @@ class SentrySDKTests: XCTestCase { XCTAssertEqual(0, hub.installedIntegrations.count) assertIntegrationsInstalled(integrations: []) } + +#if SENTRY_HAS_UIKIT + func testClose_StopsAppStateManager() { + SentrySDK.start { options in + options.dsn = SentrySDKTests.dsnAsString + options.tracesSampleRate = 1 + } + + let appStateManager = SentryDependencyContainer.sharedInstance().appStateManager + XCTAssertEqual(appStateManager.startCount, 1) + + SentrySDK.start { options in + options.dsn = SentrySDKTests.dsnAsString + options.tracesSampleRate = 1 + } + + XCTAssertEqual(appStateManager.startCount, 2) + + SentrySDK.close() + + XCTAssertEqual(appStateManager.startCount, 0) + + let stateAfterStop = fixture.fileManager.readAppState() + XCTAssertFalse(stateAfterStop!.isSDKRunning) + } +#endif + + func testClose_SetsClientToNil() { + SentrySDK.start { options in + options.dsn = SentrySDKTests.dsnAsString + } + + SentrySDK.close() + + XCTAssertNil(SentrySDK.currentHub().client()) + } + + func testClose_ClosesClient() { + SentrySDK.start { options in + options.dsn = SentrySDKTests.dsnAsString + } + + let client = SentrySDK.currentHub().client() + SentrySDK.close() + + XCTAssertFalse(client?.isEnabled ?? true) + } + + func testClose_CallsFlushCorrectlyOnTransport() { + SentrySDK.start { options in + options.dsn = SentrySDKTests.dsnAsString + } + + let transport = TestTransport() + let client = SentryClient(options: fixture.options) + Dynamic(client).transportAdapter = TestTransportAdapter(transport: transport, options: fixture.options) + SentrySDK.currentHub().bindClient(client) + SentrySDK.close() + + XCTAssertEqual(Options().shutdownTimeInterval, transport.flushInvocations.first) + } func testFlush_CallsFlushCorrectlyOnTransport() { SentrySDK.start { options in diff --git a/scripts/xcode-test.sh b/scripts/xcode-test.sh index 08ed9f176b..5f4a35a09f 100755 --- a/scripts/xcode-test.sh +++ b/scripts/xcode-test.sh @@ -65,10 +65,10 @@ if [ $PLATFORM == "iOS" -a $OS == "12.4" ]; then GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES -destination "$DESTINATION" \ -skip-testing:"SentryTests/SentrySDKTests/testMemoryFootprintOfAddingBreadcrumbs" \ -skip-testing:"SentryTests/SentrySDKTests/testMemoryFootprintOfTransactions" \ - test | tee raw-test-output.log | $RUBY_ENV_ARGS xcpretty -t && exit ${PIPESTATUS[0]} + test | tee raw-test-output.log | $RUBY_ENV_ARGS xcpretty -t -r junit && exit ${PIPESTATUS[0]} else env NSUnbufferedIO=YES xcodebuild -workspace Sentry.xcworkspace \ -scheme Sentry -configuration $CONFIGURATION \ GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES -destination "$DESTINATION" \ - test | tee raw-test-output.log | $RUBY_ENV_ARGS xcpretty -t && exit ${PIPESTATUS[0]} + test | tee raw-test-output.log | $RUBY_ENV_ARGS xcpretty -t -r junit && exit ${PIPESTATUS[0]} fi