diff --git a/src/client/ios/Breakpad.h b/src/client/ios/Breakpad.h index c099ad07..30b13449 100644 --- a/src/client/ios/Breakpad.h +++ b/src/client/ios/Breakpad.h @@ -202,6 +202,9 @@ int BreakpadGetCrashReportCount(BreakpadRef ref); // Returns the next upload configuration. The report file is deleted. NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref); +// Returns the date of the most recent crash report. +NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref); + // Upload next report to the server. void BreakpadUploadNextReport(BreakpadRef ref); diff --git a/src/client/ios/Breakpad.mm b/src/client/ios/Breakpad.mm index c2a4202a..d7dc78c6 100644 --- a/src/client/ios/Breakpad.mm +++ b/src/client/ios/Breakpad.mm @@ -161,6 +161,7 @@ class Breakpad { NSArray *CrashReportsToUpload(); NSString *NextCrashReportToUpload(); NSDictionary *NextCrashReportConfiguration(); + NSDate *DateOfMostRecentCrashReport(); void UploadNextReport(NSDictionary *server_parameters); void UploadReportWithConfiguration(NSDictionary *configuration, NSDictionary *server_parameters); @@ -467,6 +468,30 @@ NSDictionary *Breakpad::NextCrashReportConfiguration() { return [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()]; } +//============================================================================= +NSDate *Breakpad::DateOfMostRecentCrashReport() { + NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); + if (!directory) { + return nil; + } + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSArray *dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil]; + NSArray *dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate + predicateWithFormat:@"self ENDSWITH '.dmp'"]]; + NSDate *mostRecentCrashReportDate = nil; + for (NSString *dump in dumps) { + NSString *filePath = [directory stringByAppendingPathComponent:dump]; + NSDate *crashReportDate = + [[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate]; + if (!mostRecentCrashReportDate) { + mostRecentCrashReportDate = crashReportDate; + } else if (crashReportDate) { + mostRecentCrashReportDate = [mostRecentCrashReportDate laterDate:crashReportDate]; + } + } + return mostRecentCrashReportDate; +} + //============================================================================= void Breakpad::HandleNetworkResponse(NSDictionary *configuration, NSData *data, @@ -840,6 +865,19 @@ NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) { return nil; } +//============================================================================= +NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) { + try { + Breakpad *breakpad = (Breakpad *)ref; + if (breakpad) { + return breakpad->DateOfMostRecentCrashReport(); + } + } catch (...) { // don't let exceptions leave this C API + fprintf(stderr, "BreakpadGetDateOfMostRecentCrashReport() : error\n"); + } + return nil; +} + //============================================================================= void BreakpadUploadReportWithParametersAndConfiguration( BreakpadRef ref, diff --git a/src/client/ios/BreakpadController.h b/src/client/ios/BreakpadController.h index 13609cb8..20868473 100644 --- a/src/client/ios/BreakpadController.h +++ b/src/client/ios/BreakpadController.h @@ -112,6 +112,9 @@ // Unregisters the crash handlers. - (void)stop; +// Returns whether or not the controller is started. +- (BOOL)isStarted; + // Enables or disables uploading of crash reports, but does not stop the // BreakpadController. - (void)setUploadingEnabled:(BOOL)enabled; @@ -131,6 +134,9 @@ - (void)getNextReportConfigurationOrSendDelay: (void(^)(NSDictionary*, int))callback; +// Get the date of the most recent crash report. +- (void)getDateOfMostRecentCrashReport:(void(^)(NSDate *))callback; + // Sends synchronously the report specified by |configuration|. This method is // NOT thread safe and must be called from the breakpad thread. - (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration diff --git a/src/client/ios/BreakpadController.mm b/src/client/ios/BreakpadController.mm index dc5a2d1e..8d499c27 100644 --- a/src/client/ios/BreakpadController.mm +++ b/src/client/ios/BreakpadController.mm @@ -156,6 +156,10 @@ NSString* GetPlatform() { }); } +- (BOOL)isStarted { + return started_; +} + // This method must be called from the breakpad queue. - (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration withBreakpadRef:(BreakpadRef)ref { @@ -289,6 +293,18 @@ NSString* GetPlatform() { }); } +- (void)getDateOfMostRecentCrashReport:(void(^)(NSDate *))callback { + NSAssert(started_, @"The controller must be started before " + "getDateOfMostRecentCrashReport is called"); + dispatch_async(queue_, ^{ + if (!breakpadRef_) { + callback(nil); + return; + } + callback(BreakpadGetDateOfMostRecentCrashReport(breakpadRef_)); + }); +} + #pragma mark - - (int)sendDelay {