Bug 379290 - Add env var to auto submit crashes r=gsvelto draft
authorAdam Gashlin <agashlin@mozilla.com>
Thu, 07 Dec 2017 08:47:29 -0800
changeset 709138 ae9f9b5276f8b7c8cb448999ce13bd0a13c8eee2
parent 706205 781485c695e1f07b8782427d556f6570e4a8072f
child 743332 b3de22e510c9b83823f0869af1dc1bb232662ba5
push id92544
push userbmo:agashlin@mozilla.com
push dateThu, 07 Dec 2017 16:47:56 +0000
reviewersgsvelto
bugs379290
milestone59.0a1
Bug 379290 - Add env var to auto submit crashes r=gsvelto MozReview-Commit-ID: HguIy4GKMb0
toolkit/crashreporter/client/crashreporter.cpp
toolkit/crashreporter/client/crashreporter.h
toolkit/crashreporter/client/crashreporter_gtk_common.cpp
toolkit/crashreporter/client/crashreporter_linux.cpp
toolkit/crashreporter/client/crashreporter_osx.mm
toolkit/crashreporter/client/crashreporter_win.cpp
--- a/toolkit/crashreporter/client/crashreporter.cpp
+++ b/toolkit/crashreporter/client/crashreporter.cpp
@@ -39,29 +39,34 @@ using std::auto_ptr;
 namespace CrashReporter {
 
 StringTable  gStrings;
 string       gSettingsPath;
 string       gEventsPath;
 string       gPingPath;
 int          gArgc;
 char**       gArgv;
+bool         gAutoSubmit;
 
 enum SubmissionResult {Succeeded, Failed};
 
 static auto_ptr<ofstream> gLogStream(nullptr);
 static string             gReporterDumpFile;
 static string             gExtraFile;
 static string             gMemoryFile;
 
 static const char kExtraDataExtension[] = ".extra";
 static const char kMemoryReportExtension[] = ".memory.json.gz";
 
 void UIError(const string& message)
 {
+  if (gAutoSubmit) {
+    return;
+  }
+
   string errorMessage;
   if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
     char buf[2048];
     UI_SNPRINTF(buf, 2048,
                 gStrings[ST_CRASHREPORTERERROR].c_str(),
                 message.c_str());
     errorMessage = buf;
   } else {
@@ -642,36 +647,44 @@ GetProgramPath(const string& exename)
 
 int main(int argc, char** argv)
 {
   bool minidumpAllThreads = false;
 
   gArgc = argc;
   gArgv = argv;
 
+  string autoSubmitEnv = UIGetEnv("MOZ_CRASHREPORTER_AUTO_SUBMIT");
+  if (!autoSubmitEnv.empty()) {
+    gAutoSubmit = true;
+  }
+
   if (!ReadConfig()) {
     UIError("Couldn't read configuration.");
     return 0;
   }
 
-  if (!UIInit())
+  if (!UIInit()) {
     return 0;
+  }
 
   if (argc == 3) {
     if (!strcmp(argv[1], "--full")) {
       minidumpAllThreads = true;
     }
     gReporterDumpFile = argv[2];
   } else if (argc == 2) {
     gReporterDumpFile = argv[1];
   }
 
   if (gReporterDumpFile.empty()) {
     // no dump file specified, run the default UI
-    UIShowDefaultUI();
+    if (!gAutoSubmit) {
+      UIShowDefaultUI();
+    }
   } else {
     // Start by running minidump analyzer to gather stack traces.
     string reporterDumpFile = gReporterDumpFile;
     vector<string> args = { reporterDumpFile };
     if (minidumpAllThreads) {
       args.insert(args.begin(), "--full");
     }
     UIRunProgram(GetProgramPath(UI_MINIDUMP_ANALYZER_FILENAME),
@@ -805,23 +818,23 @@ int main(int argc, char** argv)
     // allow override of the server url via environment variable
     //XXX: remove this in the far future when our robot
     // masters force everyone to use XULRunner
     char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
     if (urlEnv && *urlEnv) {
       sendURL = urlEnv;
     }
 
-     // see if this version has been end-of-lifed
-     if (queryParameters.find("Version") != queryParameters.end() &&
-         CheckEndOfLifed(queryParameters["Version"])) {
-       UIError(gStrings[ST_ERROR_ENDOFLIFE]);
-       DeleteDump();
-       return 0;
-     }
+    // see if this version has been end-of-lifed
+    if (queryParameters.find("Version") != queryParameters.end() &&
+        CheckEndOfLifed(queryParameters["Version"])) {
+      UIError(gStrings[ST_ERROR_ENDOFLIFE]);
+      DeleteDump();
+      return 0;
+    }
 
     StringTable files;
     files["upload_file_minidump"] = gReporterDumpFile;
     if (!gMemoryFile.empty()) {
       files["memory_report"] = gMemoryFile;
     }
 
     if (!UIShowCrashUI(files, queryParameters, sendURL, restartArgs))
--- a/toolkit/crashreporter/client/crashreporter.h
+++ b/toolkit/crashreporter/client/crashreporter.h
@@ -88,16 +88,17 @@ typedef std::map<std::string, std::strin
 //=============================================================================
 
 namespace CrashReporter {
   extern StringTable  gStrings;
   extern std::string  gSettingsPath;
   extern std::string  gEventsPath;
   extern int          gArgc;
   extern char**       gArgv;
+  extern bool         gAutoSubmit;
 
   void UIError(const std::string& message);
 
   // The UI finished sending the report
   void SendCompleted(bool success, const std::string& serverResponse);
 
   bool ReadStrings(std::istream& in,
                    StringTable& strings,
--- a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp
+++ b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp
@@ -54,16 +54,17 @@ string gCACertificateFile;
 string gSendURL;
 string gURLParameter;
 vector<string> gRestartArgs;
 GThread* gSendThreadID;
 
 // From crashreporter_linux.cpp
 void SaveSettings();
 void SendReport();
+void DisableGUIAndSendReport();
 void TryInitGnome();
 void UpdateSubmit();
 
 static bool RestartApplication()
 {
   char** argv = reinterpret_cast<char**>(
     malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
 
@@ -88,17 +89,19 @@ static bool RestartApplication()
   free(argv);
 
   return true;
 }
 
 // Quit the app, used as a timeout callback
 static gboolean CloseApp(gpointer data)
 {
-  gtk_main_quit();
+  if (!gAutoSubmit) {
+    gtk_main_quit();
+  }
   g_thread_join(gSendThreadID);
   return FALSE;
 }
 
 static gboolean ReportCompleted(gpointer success)
 {
   gtk_widget_hide(gThrobber);
   string str = success ? gStrings[ST_REPORTSUBMITSUCCESS]
@@ -206,20 +209,23 @@ gpointer SendThread(gpointer args)
   if (success) {
     LogMessage("Crash report submitted successfully");
   }
   else {
     LogMessage("Crash report submission failed: " + error);
   }
 
   SendCompleted(success, response);
-  // Apparently glib is threadsafe, and will schedule this
-  // on the main thread, see:
-  // http://library.gnome.org/devel/gtk-faq/stable/x499.html
-  g_idle_add(ReportCompleted, (gpointer)success);
+
+  if (!gAutoSubmit) {
+    // Apparently glib is threadsafe, and will schedule this
+    // on the main thread, see:
+    // http://library.gnome.org/devel/gtk-faq/stable/x499.html
+    g_idle_add(ReportCompleted, (gpointer)success);
+  }
 
   return nullptr;
 }
 
 gboolean WindowDeleted(GtkWidget* window,
                        GdkEvent* event,
                        gpointer userData)
 {
@@ -238,17 +244,17 @@ gboolean check_escape(GtkWidget* window,
   }
   return FALSE;
 }
 
 static void MaybeSubmitReport()
 {
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
     gDidTrySend = true;
-    SendReport();
+    DisableGUIAndSendReport();
   } else {
     gtk_main_quit();
   }
 }
 
 void CloseClicked(GtkButton* button,
                   gpointer userData)
 {
--- a/toolkit/crashreporter/client/crashreporter_linux.cpp
+++ b/toolkit/crashreporter/client/crashreporter_linux.cpp
@@ -92,38 +92,42 @@ void SaveSettings()
     ? "1" : "0";
 
   WriteStringsToFile(gSettingsPath + "/" + kIniFile,
                      "Crash Reporter", settings, true);
 }
 
 void SendReport()
 {
+#ifdef MOZ_ENABLE_GCONF
+  LoadProxyinfo();
+#endif
+
+  // spawn a thread to do the sending
+  gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, nullptr);
+}
+
+void DisableGUIAndSendReport()
+{
   // disable all our gui controls, show the throbber + change the progress text
   gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
   gtk_widget_set_sensitive(gViewReportButton, FALSE);
   gtk_widget_set_sensitive(gCommentText, FALSE);
   if (gIncludeURLCheck)
     gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
   gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
   gtk_widget_set_sensitive(gEmailEntry, FALSE);
   gtk_widget_set_sensitive(gCloseButton, FALSE);
   if (gRestartButton)
     gtk_widget_set_sensitive(gRestartButton, FALSE);
   gtk_widget_show_all(gThrobber);
   gtk_label_set_text(GTK_LABEL(gProgressLabel),
                      gStrings[ST_REPORTDURINGSUBMIT].c_str());
 
-#ifdef MOZ_ENABLE_GCONF
-  LoadProxyinfo();
-#endif
-
-  // and spawn a thread to do the sending
-  GError* err;
-  gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, &err);
+  SendReport();
 }
 
 static void ShowReportInfo(GtkTextView* viewReportTextView)
 {
   GtkTextBuffer* buffer =
     gtk_text_view_get_buffer(viewReportTextView);
 
   GtkTextIter start, end;
@@ -386,16 +390,22 @@ bool UIShowCrashUI(const StringTable& fi
 {
   gFiles = files;
   gQueryParameters = queryParameters;
   gSendURL = sendURL;
   gRestartArgs = restartArgs;
   if (gQueryParameters.find("URL") != gQueryParameters.end())
     gURLParameter = gQueryParameters["URL"];
 
+  if (gAutoSubmit) {
+    SendReport();
+    CloseApp(nullptr);
+    return true;
+  }
+
   gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(gWindow),
                        gStrings[ST_CRASHREPORTERTITLE].c_str());
   gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE);
   gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER);
   gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12);
   g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0);
   g_signal_connect(gWindow, "key_press_event", G_CALLBACK(check_escape), nullptr);
--- a/toolkit/crashreporter/client/crashreporter_osx.mm
+++ b/toolkit/crashreporter/client/crashreporter_osx.mm
@@ -106,16 +106,22 @@ static bool RestartApplication()
 -(void)showCrashUI:(const StringTable&)files
    queryParameters:(const StringTable&)queryParameters
            sendURL:(const string&)sendURL
 {
   gFiles = files;
   gQueryParameters = queryParameters;
   gSendURL = sendURL;
 
+  if (gAutoSubmit) {
+    gDidTrySend = true;
+    [self sendReport];
+    return;
+  }
+
   [mWindow setTitle:Str(ST_CRASHREPORTERTITLE)];
   [mHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
 
   NSRect viewReportFrame = [mViewReportButton frame];
   [mViewReportButton setTitle:Str(ST_VIEWREPORT)];
   [mViewReportButton sizeToFit];
   if (gRTLlayout) {
     // sizeToFit will keep the left side fixed, so realign
@@ -532,22 +538,27 @@ static bool RestartApplication()
     [mEmailText setEnabled:NO];
   }
 }
 
 -(void)sendReport
 {
   if (![self setupPost]) {
     LogMessage("Crash report submission failed: could not set up POST data");
-   [self setStringFitVertically:mProgressText
+
+    if (gAutoSubmit) {
+      [NSApp terminate:self];
+    }
+
+    [self setStringFitVertically:mProgressText
                           string:Str(ST_SUBMITFAILED)
                     resizeWindow:YES];
-   // quit after 5 seconds
-   [self performSelector:@selector(closeMeDown:) withObject:nil
-    afterDelay:5.0];
+    // quit after 5 seconds
+    [self performSelector:@selector(closeMeDown:) withObject:nil
+     afterDelay:5.0];
   }
 
   [NSThread detachNewThreadSelector:@selector(uploadThread:)
             toTarget:self
             withObject:mPost];
 }
 
 -(bool)setupPost
@@ -622,16 +633,20 @@ static bool RestartApplication()
     }
     NSString* r = [[NSString alloc] initWithData: data encoding: encoding];
     reply = [r UTF8String];
     [r release];
   }
 
   SendCompleted(success, reply);
 
+  if (gAutoSubmit) {
+    [NSApp terminate:self];
+  }
+
   [mProgressIndicator stopAnimation:self];
   if (success) {
    [self setStringFitVertically:mProgressText
                           string:Str(ST_REPORTSUBMITSUCCESS)
                     resizeWindow:YES];
   } else {
    [self setStringFitVertically:mProgressText
                           string:Str(ST_SUBMITFAILED)
@@ -761,18 +776,22 @@ bool UIInit()
 {
   gMainPool = [[NSAutoreleasePool alloc] init];
   [NSApplication sharedApplication];
 
   if (gStrings.find("isRTL") != gStrings.end() &&
       gStrings["isRTL"] == "yes")
     gRTLlayout = true;
 
-  [NSBundle loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
-                   owner:NSApp];
+  if (gAutoSubmit) {
+    gUI = [[CrashReporterUI alloc] init];
+  } else {
+    [NSBundle loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
+                     owner:NSApp];
+  }
 
   return true;
 }
 
 void UIShutdown()
 {
   [gMainPool release];
 }
--- a/toolkit/crashreporter/client/crashreporter_win.cpp
+++ b/toolkit/crashreporter/client/crashreporter_win.cpp
@@ -409,17 +409,24 @@ static DWORD WINAPI SendThreadProc(LPVOI
     else {
       // get an error string and print it to the log
       //XXX: would be nice to get the HTTP status code here, filed:
       // http://code.google.com/p/google-breakpad/issues/detail?id=220
       LogMessage(FormatLastError());
     }
   }
 
-  PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0);
+  if (gAutoSubmit) {
+    // Ordinarily this is done on the main thread in CrashReporterDialogProc,
+    // for auto submit we don't run that and it should be safe to finish up
+    // here as is done on other platforms.
+    SendCompleted(finishedOk, WideToUTF8(gSendData.serverResponse));
+  } else {
+    PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0);
+  }
 
   return 0;
 }
 
 static void EndCrashReporterDialog(HWND hwndDlg, int code)
 {
   // Save the current values to the registry
   wchar_t email[MAX_EMAIL_LENGTH];
@@ -1352,16 +1359,26 @@ bool UIShowCrashUI(const StringTable& fi
     gURLParameter = gQueryParameters[L"URL"];
 
   gRestartArgs = restartArgs;
 
   if (gStrings.find("isRTL") != gStrings.end() &&
       gStrings["isRTL"] == "yes")
     gRTLlayout = true;
 
+  if (gAutoSubmit) {
+    gSendData.queryParameters = gQueryParameters;
+
+    gThreadHandle = CreateThread(nullptr, 0, SendThreadProc, &gSendData, 0,
+                                 nullptr);
+    WaitForSingleObject(gThreadHandle, INFINITE);
+    // SendCompleted was called from SendThreadProc
+    return true;
+  }
+
   return 1 == DialogBoxParamMaybeRTL(IDD_SENDDIALOG, nullptr,
                                      (DLGPROC)CrashReporterDialogProc, 0);
 }
 
 void UIError_impl(const string& message)
 {
   wstring title = Str(ST_CRASHREPORTERTITLE);
   if (title.empty())