AU: Function to trigger crash reporter.

This CL introduces a new utility function that fork()s and has the
child call abort(), thus triggering the crash reporter. The actual
work is done in a main loop callback to ensure that the stack trace is
the same for all calls to this function.

TEST=unittest (minimal), tested on device - saw crash reporter pick up the crash.
BUG=10739

Review URL: http://codereview.chromium.org/6114002

Change-Id: If3c3c43644173f2307b8498d40881c3b38b938e5
diff --git a/utils.cc b/utils.cc
index 359b6b8..95b5ec9 100644
--- a/utils.cc
+++ b/utils.cc
@@ -8,6 +8,7 @@
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -501,6 +502,27 @@
   return true;
 }
 
+namespace {
+// Do the actual trigger. We do it as a main-loop callback to (try to) get a
+// consistent stack trace.
+gboolean TriggerCrashReporterUpload(void* unused) {
+  pid_t pid = fork();
+  CHECK(pid >= 0) << "fork failed";  // fork() failed. Something is very wrong.
+  if (pid == 0) {
+    // We are the child. Crash.
+    abort();  // never returns
+  }
+  // We are the parent. Wait for child to terminate.
+  pid_t result = waitpid(pid, NULL, 0);
+  LOG_IF(ERROR, result < 0) << "waitpid() failed";
+  return FALSE;  // Don't call this callback again
+}
+}  // namespace {}
+
+void ScheduleCrashReporterUpload() {
+  g_idle_add(&TriggerCrashReporterUpload, NULL);
+}
+
 bool SetProcessPriority(ProcessPriority priority) {
   int prio = static_cast<int>(priority);
   LOG(INFO) << "Setting process priority to " << prio;
diff --git a/utils.h b/utils.h
index 4979636..776fc22 100644
--- a/utils.h
+++ b/utils.h
@@ -141,6 +141,10 @@
 // Initiates a system reboot. Returns true on success, false otherwise.
 bool Reboot();
 
+// Schedules a Main Loop callback to trigger the crash reporter to perform an
+// upload as if this process had crashed.
+void ScheduleCrashReporterUpload();
+
 // Fuzzes an integer |value| randomly in the range:
 // [value - range / 2, value + range - range / 2]
 int FuzzInt(int value, unsigned int range);
diff --git a/utils_unittest.cc b/utils_unittest.cc
index d8bc866..185ab9a 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -255,4 +255,22 @@
   EXPECT_EQ(10 * 1024 * 1024 / 4096, block_count);
 }
 
+namespace {
+gboolean  TerminateScheduleCrashReporterUploadTest(void* arg) {
+  GMainLoop* loop = reinterpret_cast<GMainLoop*>(arg);
+  g_main_loop_quit(loop);
+  return FALSE;  // Don't call this callback again
+}
+}  // namespace {}
+
+TEST(UtilsTest, ScheduleCrashReporterUploadTest) {
+  // Not much to test. At least this tests for memory leaks, crashes,
+  // log errors.
+  GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
+  utils::ScheduleCrashReporterUpload();
+  g_timeout_add_seconds(1, &TerminateScheduleCrashReporterUploadTest, loop);
+  g_main_loop_run(loop);
+  g_main_loop_unref(loop);
+}
+
 }  // namespace chromeos_update_engine