Adds method to get the date of the most recent iOS crash report.

Also adds method to determine if breakpad is started.

Change-Id: I272765e7ac6bbc07d77ca2d8dcc34d51c205116e
Reviewed-on: https://chromium-review.googlesource.com/c/1260625
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
diff --git a/src/client/ios/Breakpad.h b/src/client/ios/Breakpad.h
index c099ad0..30b1344 100644
--- a/src/client/ios/Breakpad.h
+++ b/src/client/ios/Breakpad.h
@@ -202,6 +202,9 @@
 // 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 c2a4202..d7dc78c 100644
--- a/src/client/ios/Breakpad.mm
+++ b/src/client/ios/Breakpad.mm
@@ -161,6 +161,7 @@
   NSArray *CrashReportsToUpload();
   NSString *NextCrashReportToUpload();
   NSDictionary *NextCrashReportConfiguration();
+  NSDate *DateOfMostRecentCrashReport();
   void UploadNextReport(NSDictionary *server_parameters);
   void UploadReportWithConfiguration(NSDictionary *configuration,
                                      NSDictionary *server_parameters);
@@ -468,6 +469,30 @@
 }
 
 //=============================================================================
+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,
                                      NSError *error) {
@@ -841,6 +866,19 @@
 }
 
 //=============================================================================
+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,
     NSDictionary *server_parameters,
diff --git a/src/client/ios/BreakpadController.h b/src/client/ios/BreakpadController.h
index 13609cb..2086847 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 dc5a2d1..8d499c2 100644
--- a/src/client/ios/BreakpadController.mm
+++ b/src/client/ios/BreakpadController.mm
@@ -156,6 +156,10 @@
   });
 }
 
+- (BOOL)isStarted {
+  return started_;
+}
+
 // This method must be called from the breakpad queue.
 - (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration
                                 withBreakpadRef:(BreakpadRef)ref {
@@ -289,6 +293,18 @@
   });
 }
 
+- (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 {