diff --git a/Classes/BITCrashDetails.h b/Classes/BITCrashDetails.h new file mode 100644 index 0000000000..1c5988f71b --- /dev/null +++ b/Classes/BITCrashDetails.h @@ -0,0 +1,35 @@ +// +// BITCrashDetails.h +// HockeySDK +// +// Created by Andreas Linde on 03.04.14. +// +// + +#import + +@interface BITCrashDetails : NSObject + +@property (nonatomic, readonly, strong) NSString *incidentIdentifier; + +@property (nonatomic, readonly, strong) NSString *reporterKey; + +@property (nonatomic, readonly, strong) NSString *signal; + +@property (nonatomic, readonly, strong) NSString *exceptionName; + +@property (nonatomic, readonly, strong) NSString *exceptionReason; + +@property (nonatomic, readonly, strong) NSDate *appStartTime; + +@property (nonatomic, readonly, strong) NSDate *crashTime; + +- (instancetype)initWithIncidentIdentifier:(NSString *)incidentIdentifier + reporterKey:(NSString *)reporterKey + signal:(NSString *)signal + exceptionName:(NSString *)exceptionName + exceptionReason:(NSString *)exceptionReason + appStartTime:(NSDate *)appStartTime + crashTime:(NSDate *)crashTime; + +@end diff --git a/Classes/BITCrashDetails.m b/Classes/BITCrashDetails.m new file mode 100644 index 0000000000..d201fac9c1 --- /dev/null +++ b/Classes/BITCrashDetails.m @@ -0,0 +1,33 @@ +// +// BITCrashDetails.m +// HockeySDK +// +// Created by Andreas Linde on 03.04.14. +// +// + +#import "BITCrashDetails.h" + +@implementation BITCrashDetails + +- (instancetype)initWithIncidentIdentifier:(NSString *)incidentIdentifier + reporterKey:(NSString *)reporterKey + signal:(NSString *)signal + exceptionName:(NSString *)exceptionName + exceptionReason:(NSString *)exceptionReason + appStartTime:(NSDate *)appStartTime + crashTime:(NSDate *)crashTime; +{ + if ((self = [super init])) { + _incidentIdentifier = incidentIdentifier; + _reporterKey = reporterKey; + _signal = signal; + _exceptionName = exceptionName; + _exceptionReason = exceptionReason; + _appStartTime = appStartTime; + _crashTime = crashTime; + } + return self; +} + +@end diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index b958cc8913..6025d95b7c 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -32,12 +32,7 @@ #import "BITHockeyBaseManager.h" -// We need this check depending on integrating as a subproject or using the binary distribution -#if __has_include("CrashReporter.h") -#import "CrashReporter.h" -#else -#import -#endif +@class BITCrashDetails; /** @@ -299,6 +294,12 @@ typedef NS_ENUM(NSUInteger, BITCrashManagerStatus) { @property (nonatomic, readonly) BOOL wasKilledInLastSession; +/** + * Provides details about the crash that occured in the last app session + */ +@property (nonatomic, readonly) BITCrashDetails *lastSessionCrashDetails; + + /** Indicates if the app did receive a low memory warning in the last session diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index bbdef08496..6ce744277e 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -612,8 +612,12 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; if (report == nil) { BITHockeyLog(@"WARNING: Could not parse crash report"); } else { + NSDate *appStartTime = nil; + NSDate *appCrashTime = nil; if ([report.processInfo respondsToSelector:@selector(processStartTime)]) { if (report.systemInfo.timestamp && report.processInfo.processStartTime) { + appStartTime = report.processInfo.processStartTime; + appCrashTime =report.systemInfo.timestamp; _timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.processInfo.processStartTime]; } } @@ -621,6 +625,22 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; [crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES]; [self storeMetaDataForCrashReportFilename:cacheFilename]; + + NSString *incidentIdentifier = @"???"; + if (report.uuidRef != NULL) { + incidentIdentifier = (NSString *) CFBridgingRelease(CFUUIDCreateString(NULL, report.uuidRef)); + } + + NSString *reporterKey = bit_appAnonID() ?: @""; + + _lastSessionCrashDetails = [[BITCrashDetails alloc] initWithIncidentIdentifier:incidentIdentifier + reporterKey:reporterKey + signal:report.signalInfo.name + exceptionName:report.exceptionInfo.exceptionName + exceptionReason:report.exceptionInfo.exceptionReason + appStartTime:appStartTime + crashTime:appCrashTime + ]; } } } @@ -896,6 +916,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; */ - (void)createCrashReportForAppKill { NSString *fakeReportUUID = bit_UUID(); + NSString *fakeReporterKey = bit_appAnonID() ?: @"???"; NSString *fakeReportAppVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kBITAppVersion]; if (!fakeReportAppVersion) @@ -906,10 +927,12 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; NSString *fakeReportDeviceModel = [self getDevicePlatform] ?: @"Unknown"; NSString *fakeReportAppUUIDs = [[NSUserDefaults standardUserDefaults] objectForKey:kBITAppUUIDs] ?: @""; + NSString *fakeSignalName = @"SIGKILL"; + NSMutableString *fakeReportString = [NSMutableString string]; [fakeReportString appendFormat:@"Incident Identifier: %@\n", fakeReportUUID]; - [fakeReportString appendFormat:@"CrashReporter Key: %@\n", bit_appAnonID() ?: @"???"]; + [fakeReportString appendFormat:@"CrashReporter Key: %@\n", fakeReporterKey]; [fakeReportString appendFormat:@"Hardware Model: %@\n", fakeReportDeviceModel]; [fakeReportString appendFormat:@"Identifier: %@\n", fakeReportAppBundleIdentifier]; [fakeReportString appendFormat:@"Version: %@\n", fakeReportAppVersion]; @@ -921,13 +944,14 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; [rfc3339Formatter setLocale:enUSPOSIXLocale]; [rfc3339Formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; [rfc3339Formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + NSString *fakeCrashTimestamp = [rfc3339Formatter stringFromDate:[NSDate date]]; // we use the current date, since we don't know when the kill actually happened - [fakeReportString appendFormat:@"Date/Time: %@\n", [rfc3339Formatter stringFromDate:[NSDate date]]]; + [fakeReportString appendFormat:@"Date/Time: %@\n", fakeCrashTimestamp]; [fakeReportString appendFormat:@"OS Version: %@\n", fakeReportOSVersion]; [fakeReportString appendString:@"Report Version: 104\n"]; [fakeReportString appendString:@"\n"]; - [fakeReportString appendString:@"Exception Type: SIGKILL\n"]; + [fakeReportString appendFormat:@"Exception Type: %@\n", fakeSignalName]; [fakeReportString appendString:@"Exception Codes: 00000020 at 0x8badf00d\n"]; [fakeReportString appendString:@"\n"]; [fakeReportString appendString:@"Application Specific Information:\n"]; @@ -950,6 +974,15 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; [rootObj setObject:fakeReportAppUUIDs forKey:kBITFakeCrashAppBinaryUUID]; [rootObj setObject:fakeReportString forKey:kBITFakeCrashReport]; + _lastSessionCrashDetails = [[BITCrashDetails alloc] initWithIncidentIdentifier:fakeReportUUID + reporterKey:fakeReporterKey + signal:fakeSignalName + exceptionName:nil + exceptionReason:nil + appStartTime:nil + crashTime:nil + ]; + NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj format:NSPropertyListBinaryFormat_v1_0 errorDescription:&errorString]; diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index aa1c4da3ff..fe9d7b9837 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -38,6 +38,7 @@ #if HOCKEYSDK_FEATURE_CRASH_REPORTER #import "BITCrashManager.h" #import "BITCrashManagerDelegate.h" +#import "BITCrashDetails.h" #endif /* HOCKEYSDK_FEATURE_CRASH_REPORTER */ #if HOCKEYSDK_FEATURE_UPDATES || HOCKEYSDK_FEATURE_JIRA_MOBILE_CONNECT diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 910428df15..8627e93a9f 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -111,6 +111,8 @@ 1E7A45FC16F54FB5005B08F1 /* OCHamcrestIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E7A45FA16F54FB5005B08F1 /* OCHamcrestIOS.framework */; }; 1E7A45FD16F54FB5005B08F1 /* OCMockitoIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E7A45FB16F54FB5005B08F1 /* OCMockitoIOS.framework */; }; 1E84DB3417E099BA00AC83FD /* HockeySDKFeatureConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E84DB3317E0977C00AC83FD /* HockeySDKFeatureConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E90FD7318EDB86400CF0417 /* BITCrashDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E90FD7118EDB86400CF0417 /* BITCrashDetails.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E90FD7418EDB86400CF0417 /* BITCrashDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E90FD7218EDB86400CF0417 /* BITCrashDetails.m */; }; 1E94F9E116E91330006570AD /* BITStoreUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E94F9DF16E91330006570AD /* BITStoreUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E94F9E216E91330006570AD /* BITStoreUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E94F9E016E91330006570AD /* BITStoreUpdateManager.m */; }; 1E94F9E416E9136B006570AD /* BITStoreUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E94F9E316E9136B006570AD /* BITStoreUpdateManagerPrivate.h */; }; @@ -268,6 +270,8 @@ 1E7A45FA16F54FB5005B08F1 /* OCHamcrestIOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OCHamcrestIOS.framework; sourceTree = ""; }; 1E7A45FB16F54FB5005B08F1 /* OCMockitoIOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OCMockitoIOS.framework; sourceTree = ""; }; 1E84DB3317E0977C00AC83FD /* HockeySDKFeatureConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HockeySDKFeatureConfig.h; sourceTree = ""; }; + 1E90FD7118EDB86400CF0417 /* BITCrashDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashDetails.h; sourceTree = ""; }; + 1E90FD7218EDB86400CF0417 /* BITCrashDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashDetails.m; sourceTree = ""; }; 1E94F9DF16E91330006570AD /* BITStoreUpdateManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITStoreUpdateManager.h; sourceTree = ""; }; 1E94F9E016E91330006570AD /* BITStoreUpdateManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITStoreUpdateManager.m; sourceTree = ""; }; 1E94F9E316E9136B006570AD /* BITStoreUpdateManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITStoreUpdateManagerPrivate.h; sourceTree = ""; }; @@ -478,6 +482,8 @@ children = ( 1E754E561621FBB70070AB92 /* BITCrashManager.h */, 1E754E571621FBB70070AB92 /* BITCrashManager.m */, + 1E90FD7118EDB86400CF0417 /* BITCrashDetails.h */, + 1E90FD7218EDB86400CF0417 /* BITCrashDetails.m */, 1EFF03D717F20F8300A5F13C /* BITCrashManagerPrivate.h */, 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */, 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */, @@ -635,6 +641,7 @@ 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */, 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */, + 1E90FD7318EDB86400CF0417 /* BITCrashDetails.h in Headers */, 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, @@ -886,6 +893,7 @@ 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */, 1E49A4C7161222B900463151 /* BITAppStoreHeader.m in Sources */, 1E49A4CD161222B900463151 /* BITStoreButton.m in Sources */, + 1E90FD7418EDB86400CF0417 /* BITCrashDetails.m in Sources */, 1E49A4D3161222B900463151 /* BITWebTableViewCell.m in Sources */, E48A3DED17B3ED1C00924C3D /* BITAuthenticator.m in Sources */, 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */,