Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add screenshot at crash #1920

Merged
merged 33 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4ba0322
SentryCrash screenshot callback
brustolin Jun 22, 2022
9494db5
add screenshot attachment
brustolin Jun 27, 2022
cc44cca
Merge branch 'master' into feat/crash-screenshot
brustolin Jun 27, 2022
aca1443
Format code
getsentry-bot Jun 27, 2022
a4bad19
Update CHANGELOG.md
brustolin Jun 27, 2022
8c5465c
Merge branch 'feat/crash-screenshot' of https://github.com/getsentry/…
brustolin Jun 27, 2022
66820bc
Apply suggestions from code review
brustolin Jun 28, 2022
23d3536
Improvements with file interactions
brustolin Jun 28, 2022
ae6b9e0
Merge branch 'master' into feat/crash-screenshot
brustolin Jun 28, 2022
d60054c
string format
brustolin Jun 28, 2022
4eadd21
Format code
getsentry-bot Jun 28, 2022
dcfb4f9
Merge branch 'master' into feat/crash-screenshot
brustolin Jun 29, 2022
7f66d8d
Merge branch 'feat/crash-screenshot' of https://github.com/getsentry/…
brustolin Jun 29, 2022
a723c7a
Report sink test
brustolin Jun 29, 2022
636bcbe
integration test
brustolin Jun 30, 2022
511864a
Update SentryScreenshot.m
brustolin Jun 30, 2022
db0865e
Merge branch 'master' into feat/crash-screenshot
brustolin Jun 30, 2022
e2fa1f2
tests
brustolin Jul 1, 2022
ceb5fbe
Format code
getsentry-bot Jul 1, 2022
453dddf
Update SentryCrash.m
brustolin Jul 1, 2022
cbe448f
Merge branch 'feat/crash-screenshot' of https://github.com/getsentry/…
brustolin Jul 1, 2022
60a7c2e
Update SentryCrashReportStore.c
brustolin Jul 1, 2022
5229655
Format code
getsentry-bot Jul 1, 2022
da48b93
Apply suggestions from code review
brustolin Jul 6, 2022
dbf5d0b
testfs
brustolin Jul 6, 2022
bd84076
Merge branch 'feat/crash-screenshot' of https://github.com/getsentry/…
brustolin Jul 6, 2022
64845d0
Update SentryCrash.m
brustolin Jul 6, 2022
6a66e78
Format code
getsentry-bot Jul 6, 2022
0b5531a
Update SentryCrashReportStore_Tests.m
brustolin Jul 6, 2022
9b880f6
Format code
getsentry-bot Jul 6, 2022
8c66ac8
more fixes
brustolin Jul 6, 2022
068179d
Merge branch 'feat/crash-screenshot' of https://github.com/getsentry/…
brustolin Jul 6, 2022
bf6008e
Merge branch 'master' into feat/crash-screenshot
brustolin Jul 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Add screenshot at crash (#1920)
- Add main thread ID to profiling payload (#1918)
- Add App Hangs tracking (#1906)

Expand Down
8 changes: 8 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@
A811D867248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */; };
A839D89824864B80003B7AFD /* SentrySystemEventBreadcrumbs.h in Headers */ = {isa = PBXBuildFile; fileRef = A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */; };
A839D89A24864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m in Sources */ = {isa = PBXBuildFile; fileRef = A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */; };
D8019910286B089000C277F0 /* SentryCrashReportSinkTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */; };
D808FB88281AB33C009A2A33 /* SentryUIEventTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808FB86281AB31D009A2A33 /* SentryUIEventTrackerTests.swift */; };
D808FB8B281BCE96009A2A33 /* TestSentrySwizzleWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808FB89281BCE46009A2A33 /* TestSentrySwizzleWrapper.swift */; };
D808FB92281BF6EC009A2A33 /* SentryUIEventTrackingIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808FB90281BF6E9009A2A33 /* SentryUIEventTrackingIntegrationTests.swift */; };
Expand All @@ -627,6 +628,7 @@
D84793262788737D00BE8E99 /* SentryByteCountFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = D84793242788737D00BE8E99 /* SentryByteCountFormatter.m */; };
D8479328278873A100BE8E99 /* SentryByteCountFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = D8479327278873A100BE8E99 /* SentryByteCountFormatter.h */; };
D85596F3280580F10041FF8B /* SentryScreenshotIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = D85596F1280580F10041FF8B /* SentryScreenshotIntegration.m */; };
D855AD62286ED6A4002573E1 /* SentryCrashTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D855AD61286ED6A4002573E1 /* SentryCrashTests.m */; };
D855B3E827D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D855B3E727D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift */; };
D855B3EA27D652C700BCED76 /* TestCoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D855B3E927D652C700BCED76 /* TestCoreDataStack.swift */; };
D85852B627ECEEDA00C6D8AE /* SentryScreenshot.m in Sources */ = {isa = PBXBuildFile; fileRef = D85852B427ECEEDA00C6D8AE /* SentryScreenshot.m */; };
Expand Down Expand Up @@ -1351,6 +1353,7 @@
A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySystemEventBreadcrumbsTest.swift; sourceTree = "<group>"; };
A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySystemEventBreadcrumbs.h; path = include/SentrySystemEventBreadcrumbs.h; sourceTree = "<group>"; };
A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySystemEventBreadcrumbs.m; sourceTree = "<group>"; };
D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCrashReportSinkTest.swift; sourceTree = "<group>"; };
D808FB86281AB31D009A2A33 /* SentryUIEventTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUIEventTrackerTests.swift; sourceTree = "<group>"; };
D808FB89281BCE46009A2A33 /* TestSentrySwizzleWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentrySwizzleWrapper.swift; sourceTree = "<group>"; };
D808FB90281BF6E9009A2A33 /* SentryUIEventTrackingIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUIEventTrackingIntegrationTests.swift; sourceTree = "<group>"; };
Expand All @@ -1362,6 +1365,7 @@
D84793242788737D00BE8E99 /* SentryByteCountFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryByteCountFormatter.m; sourceTree = "<group>"; };
D8479327278873A100BE8E99 /* SentryByteCountFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryByteCountFormatter.h; path = include/SentryByteCountFormatter.h; sourceTree = "<group>"; };
D85596F1280580F10041FF8B /* SentryScreenshotIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryScreenshotIntegration.m; sourceTree = "<group>"; };
D855AD61286ED6A4002573E1 /* SentryCrashTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashTests.m; sourceTree = "<group>"; };
D855B3E727D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCoreDataTrackingIntegrationTest.swift; sourceTree = "<group>"; };
D855B3E927D652C700BCED76 /* TestCoreDataStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestCoreDataStack.swift; sourceTree = "<group>"; };
D85852B427ECEEDA00C6D8AE /* SentryScreenshot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryScreenshot.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2028,6 +2032,7 @@
63FE71F120DA66EA00CDBAE8 /* Container+DeepSearch_Tests.m */,
63FE71F620DA66EB00CDBAE8 /* FileBasedTestCase.h */,
63FE71D920DA66E700CDBAE8 /* FileBasedTestCase.m */,
D855AD61286ED6A4002573E1 /* SentryCrashTests.m */,
63FE71E220DA66E800CDBAE8 /* NSError+SimpleConstructor_Tests.m */,
63FE71D520DA66E600CDBAE8 /* RFC3339UTFString_Tests.m */,
63FE71E520DA66E800CDBAE8 /* SentryCrashCachedData_Tests.m */,
Expand Down Expand Up @@ -2067,6 +2072,7 @@
7B6D98EA24C6E84F005502FA /* SentryCrashInstallationReporterTests.swift */,
7B0A542D2521C62400A71716 /* SentryFrameRemoverTests.swift */,
7BBC827825DFD7D7005F1ED8 /* SentryInAppLogicTests.swift */,
D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */,
7BED3574266F7BC600EAA70D /* TestSentryCrashWrapper.h */,
7BED3575266F7BFF00EAA70D /* TestSentryCrashWrapper.m */,
);
Expand Down Expand Up @@ -3380,6 +3386,7 @@
7B6C5ED6264E62CA0010D138 /* SentryTransactionTests.swift in Sources */,
D81FDF12280EA1060045E0E4 /* SentryScreenShotTests.swift in Sources */,
7BE3C7772445E50A00A38442 /* TestCurrentDateProvider.swift in Sources */,
D8019910286B089000C277F0 /* SentryCrashReportSinkTest.swift in Sources */,
D885266427739D01001269FC /* SentryFileIOTrackingIntegrationTests.swift in Sources */,
7BBD18992449DE9D00427C76 /* TestRateLimits.swift in Sources */,
8E4A038625F76A7600000D77 /* TypeMapping.swift in Sources */,
Expand Down Expand Up @@ -3417,6 +3424,7 @@
7BFC16BA2524D4AF00FF6266 /* SentryMessage+Equality.m in Sources */,
7B4260342630315C00B36EDD /* SampleError.swift in Sources */,
D855B3E827D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift in Sources */,
D855AD62286ED6A4002573E1 /* SentryCrashTests.m in Sources */,
D880E3A728573E87008A90DB /* SentryBaggageTests.swift in Sources */,
7B16FD022654F86B008177D3 /* SentrySysctlTests.swift in Sources */,
7BAF3DB5243C743E008A5414 /* SentryClientTests.swift in Sources */,
Expand Down
1 change: 0 additions & 1 deletion Sources/Sentry/SentryCrashReportConverter.m
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ - (SentryEvent *_Nullable)convertReportToEvent
[NSString stringWithFormat:@"Could not convert report:%@", exception.description];
[SentryLog logWithMessage:errorMessage andLevel:kSentryLevelError];
}

return nil;
}

Expand Down
12 changes: 11 additions & 1 deletion Sources/Sentry/SentryCrashReportSink.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "SentryCrashReportSink.h"
#import "SentryAttachment.h"
#import "SentryClient.h"
#import "SentryCrash.h"
#import "SentryCrashReportConverter.h"
Expand All @@ -9,6 +10,7 @@
#import "SentryLog.h"
#import "SentrySDK+Private.h"
#import "SentrySDK.h"
#import "SentryScope.h"
#import "SentryThread.h"

@interface
Expand All @@ -33,7 +35,15 @@ - (void)handleConvertedEvent:(SentryEvent *)event
sentReports:(NSMutableArray *)sentReports
{
[sentReports addObject:report];
[SentrySDK captureCrashEvent:event];
SentryScope *scope = [[SentryScope alloc] initWithScope:SentrySDK.currentHub.scope];

if (report[SENTRYCRASH_REPORT_SCREENSHOT_ITEM]) {
for (NSString *ssPath in report[SENTRYCRASH_REPORT_SCREENSHOT_ITEM]) {
[scope addAttachment:[[SentryAttachment alloc] initWithPath:ssPath]];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h: When do we delete the screenshots? The attachments will be read when the SDK creates the envelope. How do we know that the screenshots are still stored on disk? Maybe it's better to read the attachments already here, and use SentryAttachment .initWithData. Then we could delete them already here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshots are deleted alongside the report. We had a code for that already.
Lets say we fail to transmit the report, on the next attempt the files won't be there, I rather have the current mechanism that deletes it.

}
}

[SentrySDK captureCrashEvent:event withScope:scope];
}

- (void)filterReports:(NSArray *)reports
Expand Down
11 changes: 8 additions & 3 deletions Sources/Sentry/SentryHub.m
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,18 @@ - (nullable SentrySession *)incrementSessionErrors
return sessionCopy;
}

- (void)captureCrashEvent:(SentryEvent *)event
{
[self captureCrashEvent:event withScope:self.scope];
}

/**
* If autoSessionTracking is enabled we want to send the crash and the event together to get proper
* numbers for release health statistics. If there are multiple crash events to be sent on the start
* of the SDK there is currently no way to know which one belongs to the crashed session so we just
* send the session with the first crashed event we receive.
*/
- (void)captureCrashEvent:(SentryEvent *)event
- (void)captureCrashEvent:(SentryEvent *)event withScope:(SentryScope *)scope
{
event.isCrashEvent = YES;

Expand All @@ -226,13 +231,13 @@ - (void)captureCrashEvent:(SentryEvent *)event
// It can be that there is no session yet, because autoSessionTracking was just enabled and
// there is a previous crash on disk. In this case we just send the crash event.
if (nil != crashedSession) {
[client captureCrashEvent:event withSession:crashedSession withScope:self.scope];
[client captureCrashEvent:event withSession:crashedSession withScope:scope];
[fileManager deleteCrashedSession];
return;
}
}

[client captureCrashEvent:event withScope:self.scope];
[client captureCrashEvent:event withScope:scope];
}

- (SentryId *)captureTransaction:(SentryTransaction *)transaction withScope:(SentryScope *)scope
Expand Down
5 changes: 5 additions & 0 deletions Sources/Sentry/SentrySDK.m
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ + (void)captureCrashEvent:(SentryEvent *)event
[SentrySDK.currentHub captureCrashEvent:event];
}

+ (void)captureCrashEvent:(SentryEvent *)event withScope:(SentryScope *)scope
{
[SentrySDK.currentHub captureCrashEvent:event withScope:scope];
}

+ (SentryId *)captureEvent:(SentryEvent *)event
{
return [SentrySDK captureEvent:event withScope:SentrySDK.currentHub.scope];
Expand Down
55 changes: 37 additions & 18 deletions Sources/Sentry/SentryScreenshot.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,9 @@ @implementation SentryScreenshot

- (NSArray<NSData *> *)appScreenshots
{
__block NSMutableArray *result;
__block NSArray *result;

void (^takeScreenShot)(void) = ^{
NSArray<UIWindow *> *windows =
[SentryDependencyContainer.sharedInstance.application windows];

result = [NSMutableArray arrayWithCapacity:windows.count];

for (UIWindow *window in windows) {
UIGraphicsBeginImageContext(window.frame.size);

if ([window drawViewHierarchyInRect:window.bounds afterScreenUpdates:false]) {
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
[result addObject:UIImagePNGRepresentation(img)];
}

UIGraphicsEndImageContext();
}
};
void (^takeScreenShot)(void) = ^{ result = [self takeScreenshots]; };

if ([NSThread isMainThread]) {
takeScreenShot();
Expand All @@ -38,6 +22,41 @@ @implementation SentryScreenshot
return result;
}

- (void)saveScreenShots:(NSString *)path
{
// This function does not dispatch the screenshot to the main thread.
// The caller should be aware of that.
// We done this way because we use this function to save screenshots
brustolin marked this conversation as resolved.
Show resolved Hide resolved
// during signal handling, and if we dispatch it to the main thread,
// that is probably blocked by the crash event, we freeze the application.
[[self takeScreenshots] enumerateObjectsUsingBlock:^(NSData *obj, NSUInteger idx, BOOL *stop) {
NSString *name = idx == 0
? @"screenshot.png"
: [NSString stringWithFormat:@"screenshot-%li.png", (unsigned long)idx + 1];
NSString *fileName = [path stringByAppendingPathComponent:name];
[obj writeToFile:fileName atomically:YES];
}];
}

- (NSArray<NSData *> *)takeScreenshots
{
NSArray<UIWindow *> *windows = [SentryDependencyContainer.sharedInstance.application windows];

NSMutableArray *result = [NSMutableArray arrayWithCapacity:windows.count];

for (UIWindow *window in windows) {
brustolin marked this conversation as resolved.
Show resolved Hide resolved
UIGraphicsBeginImageContext(window.frame.size);

if ([window drawViewHierarchyInRect:window.bounds afterScreenUpdates:false]) {
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
[result addObject:UIImagePNGRepresentation(img)];
}

UIGraphicsEndImageContext();
brustolin marked this conversation as resolved.
Show resolved Hide resolved
}
return result;
}

@end

#endif
43 changes: 38 additions & 5 deletions Sources/Sentry/SentryScreenshotIntegration.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "SentryScreenshotIntegration.h"
#import "SentryAttachment.h"
#import "SentryClient+Private.h"
#import "SentryCrashC.h"
#import "SentryDependencyContainer.h"
#import "SentryEvent+Private.h"
#import "SentryEvent.h"
Expand All @@ -10,6 +11,34 @@
#import "SentrySDK+Private.h"

#if SENTRY_HAS_UIKIT

void
saveScreenShot(const char *path)
{
NSString *reportPath = [NSString stringWithUTF8String:path];
NSError *error = nil;

if (![NSFileManager.defaultManager fileExistsAtPath:reportPath]) {
[NSFileManager.defaultManager createDirectoryAtPath:reportPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error != nil)
return;
}

// We first delete any screenshot that could be from an old crash report
NSArray *oldFiles = [NSFileManager.defaultManager contentsOfDirectoryAtPath:reportPath
brustolin marked this conversation as resolved.
Show resolved Hide resolved
brustolin marked this conversation as resolved.
Show resolved Hide resolved
error:&error];
if (!error) {
[oldFiles enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
[NSFileManager.defaultManager removeItemAtPath:obj error:nil];
}];
}

[SentryDependencyContainer.sharedInstance.screenshot saveScreenShots:reportPath];
}

@implementation SentryScreenshotIntegration

- (void)installWithOptions:(nonnull SentryOptions *)options
Expand All @@ -21,6 +50,13 @@ - (void)installWithOptions:(nonnull SentryOptions *)options

SentryClient *client = [SentrySDK.currentHub getClient];
client.attachmentProcessor = self;

sentrycrash_setSaveScreenshots(&saveScreenShot);
}

- (void)uninstall
{
sentrycrash_setSaveScreenshots(NULL);
}

- (NSArray<SentryAttachment *> *)processAttachments:(NSArray<SentryAttachment *> *)attachments
Expand All @@ -39,11 +75,8 @@ - (void)installWithOptions:(nonnull SentryOptions *)options
[result addObjectsFromArray:attachments];

for (int i = 0; i < screenshot.count; i++) {
NSString *name;
if (i == 0)
name = @"screenshot.png";
else
name = [NSString stringWithFormat:@"screenshot-%i.png", i + 1];
NSString *name
= i == 0 ? @"screenshot.png" : [NSString stringWithFormat:@"screenshot-%i.png", i + 1];

SentryAttachment *att = [[SentryAttachment alloc] initWithData:screenshot[i]
filename:name
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/SentryHub+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ SentryHub (Private)

- (void)captureCrashEvent:(SentryEvent *)event;

- (void)captureCrashEvent:(SentryEvent *)event withScope:(SentryScope *)scope;

- (void)setSampleRandomValue:(NSNumber *)value;

- (void)closeCachedSessionWithTimestamp:(NSDate *_Nullable)timestamp;
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/SentrySDK+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ SentrySDK (Private)

+ (void)captureCrashEvent:(SentryEvent *)event;

+ (void)captureCrashEvent:(SentryEvent *)event withScope:(SentryScope *)scope;

/**
* SDK private field to store the state if onCrashedLastRun was called.
*/
Expand Down
1 change: 1 addition & 0 deletions Sources/Sentry/include/SentryScreenshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSArray<NSData *> *)appScreenshots;

- (void)saveScreenShots:(NSString *)path;
@end

NS_ASSUME_NONNULL_END
Expand Down
2 changes: 2 additions & 0 deletions Sources/SentryCrash/Recording/SentryCrash.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ typedef enum {
SentryCrashCDeleteAlways
} SentryCrashCDeleteBehavior;

static NSString *const SENTRYCRASH_REPORT_SCREENSHOT_ITEM = @"screenshots";

/**
* Reports any crashes that occur in the application.
*
Expand Down
30 changes: 30 additions & 0 deletions Sources/SentryCrash/Recording/SentryCrash.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#import "SentryCrashMonitor_AppState.h"
#import "SentryCrashMonitor_System.h"
#import "SentryCrashReportFields.h"
#import "SentryCrashReportStore.h"
#import "SentryCrashSystemCapabilities.h"
#import <NSData+Sentry.h>

Expand Down Expand Up @@ -407,6 +408,28 @@ - (NSData *)loadCrashReportJSONWithID:(int64_t)reportID
return nil;
}

- (NSArray *)getScreenShots:(int64_t)reportID
brustolin marked this conversation as resolved.
Show resolved Hide resolved
{
char report_screenshot_path[SentryCrashCRS_MAX_PATH_LENGTH];
sentrycrashcrs_getScreenshotPath_forReportId(reportID, report_screenshot_path);
NSString *path = [NSString stringWithUTF8String:report_screenshot_path];

BOOL isDir = false;
if (![NSFileManager.defaultManager fileExistsAtPath:path isDirectory:&isDir] || !isDir)
return @[];

NSArray *files = [NSFileManager.defaultManager contentsOfDirectoryAtPath:path error:nil];
if (files == nil)
return @[];

NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:files.count];
[files enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
[result addObject:[NSString stringWithFormat:@"%@/%@", path, obj]];
}];

return result;
}

- (void)doctorReport:(NSMutableDictionary *)report
{
NSMutableDictionary *crashReport = report[@SentryCrashField_Crash];
Expand Down Expand Up @@ -452,6 +475,7 @@ - (NSDictionary *)reportWithIntID:(int64_t)reportID
| SentryCrashJSONDecodeOptionIgnoreNullInObject
| SentryCrashJSONDecodeOptionKeepPartialObject
error:&error];

if (error != nil) {
SentryCrashLOG_ERROR(
@"Encountered error loading crash report %" PRIx64 ": %@", reportID, error);
Expand All @@ -460,6 +484,12 @@ - (NSDictionary *)reportWithIntID:(int64_t)reportID
SentryCrashLOG_ERROR(@"Could not load crash report");
return nil;
}

NSArray *screenShots = [self getScreenShots:reportID];
if (screenShots.count > 0) {
[crashReport setObject:screenShots forKey:SENTRYCRASH_REPORT_SCREENSHOT_ITEM];
brustolin marked this conversation as resolved.
Show resolved Hide resolved
}

[self doctorReport:crashReport];

return crashReport;
Expand Down