diff --git a/mozilla/camino/Info-Camino.plist.in b/mozilla/camino/Info-Camino.plist.in index dad17f3c9b9..15778f11463 100644 --- a/mozilla/camino/Info-Camino.plist.in +++ b/mozilla/camino/Info-Camino.plist.in @@ -2,12 +2,18 @@ + BreakpadBuildID + %PLATFORM_BUILD_ID% + BreakpadConfirmTimeout + 0 BreakpadReportInterval 0 BreakpadRequestComments YES BreakpadSendAndExit NO + BreakpadServerType + socorro BreakpadURL https://crash-reports.mozilla.com/submit BreakpadVendor diff --git a/mozilla/camino/google-breakpad/README_CAMINO b/mozilla/camino/google-breakpad/README_CAMINO index 6305d6b0efa..db0f28ea614 100644 --- a/mozilla/camino/google-breakpad/README_CAMINO +++ b/mozilla/camino/google-breakpad/README_CAMINO @@ -2,6 +2,6 @@ Breakpad is an open-source library for crash reporting. See: http://code.google.com/p/google-breakpad/ for more information. -This is a pull of r330 from the svn repository at: +This is a pull of r335 from the svn repository at: http://google-breakpad.googlecode.com/svn/trunk/ with the non-mac platform directories stripped out. diff --git a/mozilla/camino/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/mozilla/camino/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj index a9ddd0178c5..7d8e5b8d366 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj +++ b/mozilla/camino/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj @@ -26,10 +26,10 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 3329D4ED0FA16D820007BBC5 /* Breakpad.nib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.nib */; }; 33880C800F9E097100817F82 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33880C7E0F9E097100817F82 /* InfoPlist.strings */; }; 4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; - F9267CB30F844BDD00A827EC /* Breakpad.nib in Resources */ = {isa = PBXBuildFile; fileRef = F9267CB10F844BDD00A827EC /* Breakpad.nib */; }; F9286B3A0F7EB25800A4DCC8 /* InspectorMain.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9286B390F7EB25800A4DCC8 /* InspectorMain.mm */; }; F92C53B80ECCE7B3009BE4BA /* Inspector.mm in Sources */ = {isa = PBXBuildFile; fileRef = F92C53B70ECCE7B3009BE4BA /* Inspector.mm */; }; F92C554C0ECCF534009BE4BA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; }; @@ -224,10 +224,10 @@ 0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpad_Prefix.pch; path = Framework/Breakpad_Prefix.pch; sourceTree = ""; }; + 3329D4EC0FA16D820007BBC5 /* Breakpad.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = Breakpad.nib; path = sender/Breakpad.nib; sourceTree = ""; }; 33880C7F0F9E097100817F82 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/InfoPlist.strings; sourceTree = ""; }; 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = crash_report_sender.icns; path = sender/crash_report_sender.icns; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* Breakpad.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Breakpad.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F9267CB20F844BDD00A827EC /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = sender/English.lproj/Breakpad.nib; sourceTree = ""; }; F9286B380F7EB25800A4DCC8 /* Inspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Inspector.h; path = crash_generation/Inspector.h; sourceTree = ""; }; F9286B390F7EB25800A4DCC8 /* InspectorMain.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = InspectorMain.mm; path = crash_generation/InspectorMain.mm; sourceTree = ""; }; F92C53540ECCE349009BE4BA /* Inspector */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Inspector; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -531,13 +531,13 @@ F92C56A60ECE04B6009BE4BA /* sender */ = { isa = PBXGroup; children = ( - F945849C0F280E3C009A47BF /* Localizable.strings */, - 33880C7E0F9E097100817F82 /* InfoPlist.strings */, - 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */, - F92C56A20ECE04A7009BE4BA /* crash_report_sender-Info.plist */, - F9267CB10F844BDD00A827EC /* Breakpad.nib */, F92C56A70ECE04C5009BE4BA /* crash_report_sender.h */, F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */, + F945849C0F280E3C009A47BF /* Localizable.strings */, + 33880C7E0F9E097100817F82 /* InfoPlist.strings */, + 3329D4EC0FA16D820007BBC5 /* Breakpad.nib */, + 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */, + F92C56A20ECE04A7009BE4BA /* crash_report_sender-Info.plist */, ); name = sender; sourceTree = ""; @@ -806,8 +806,8 @@ files = ( F945849E0F280E3C009A47BF /* Localizable.strings in Resources */, 4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */, - F9267CB30F844BDD00A827EC /* Breakpad.nib in Resources */, 33880C800F9E097100817F82 /* InfoPlist.strings in Resources */, + 3329D4ED0FA16D820007BBC5 /* Breakpad.nib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1078,14 +1078,6 @@ name = InfoPlist.strings; sourceTree = ""; }; - F9267CB10F844BDD00A827EC /* Breakpad.nib */ = { - isa = PBXVariantGroup; - children = ( - F9267CB20F844BDD00A827EC /* English */, - ); - name = Breakpad.nib; - sourceTree = ""; - }; F945849C0F280E3C009A47BF /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( diff --git a/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.h b/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.h index 06ce5ae8d2c..88be8162221 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.h +++ b/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.h @@ -61,26 +61,35 @@ extern "C" { // Specify some special keys to be used in the configuration file that is // generated by Breakpad and consumed by the crash_sender. -#define BREAKPAD_PRODUCT_DISPLAY "BreakpadProductDisplay" #define BREAKPAD_PRODUCT "BreakpadProduct" -#define BREAKPAD_VENDOR "BreakpadVendor" +#define BREAKPAD_PRODUCT_DISPLAY "BreakpadProductDisplay" #define BREAKPAD_VERSION "BreakpadVersion" +#define BREAKPAD_VENDOR "BreakpadVendor" #define BREAKPAD_URL "BreakpadURL" #define BREAKPAD_REPORT_INTERVAL "BreakpadReportInterval" #define BREAKPAD_SKIP_CONFIRM "BreakpadSkipConfirm" +#define BREAKPAD_CONFIRM_TIMEOUT "BreakpadConfirmTimeout" #define BREAKPAD_SEND_AND_EXIT "BreakpadSendAndExit" #define BREAKPAD_DUMP_DIRECTORY "BreakpadMinidumpLocation" #define BREAKPAD_INSPECTOR_LOCATION "BreakpadInspectorLocation" - #define BREAKPAD_REPORTER_EXE_LOCATION \ "BreakpadReporterExeLocation" #define BREAKPAD_LOGFILES "BreakpadLogFiles" #define BREAKPAD_LOGFILE_UPLOAD_SIZE "BreakpadLogFileTailSize" -#define BREAKPAD_LOGFILE_KEY_PREFIX "BreakpadAppLogFile" -#define BREAKPAD_EMAIL "BreakpadEmail" #define BREAKPAD_REQUEST_COMMENTS "BreakpadRequestComments" #define BREAKPAD_COMMENTS "BreakpadComments" +#define BREAKPAD_REQUEST_EMAIL "BreakpadRequestEmail" +#define BREAKPAD_EMAIL "BreakpadEmail" +#define BREAKPAD_SERVER_TYPE "BreakpadServerType" +// TODO(nealsid) find a better way to support server-specific +// parameters without having to rebuild Breakpad +#define BREAKPAD_BUILD_ID "BreakpadBuildID" +// The keys below are NOT user supplied, and are used internally. +#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime" +#define BREAKPAD_PROCESS_UP_TIME "BreakpadProcessUpTime" +#define BREAKPAD_PROCESS_CRASH_TIME "BreakpadProcessCrashTime" +#define BREAKPAD_LOGFILE_KEY_PREFIX "BreakpadAppLogFile" // Optional user-defined function to dec to decide if we should handle // this crash or forward it along. // Return true if you want Breakpad to handle it. @@ -91,9 +100,9 @@ typedef bool (*BreakpadFilterCallback)(int exception_type, int exception_code, mach_port_t crashing_thread); -// Create a new BreakpadRef object and install it as an -// exception handler. The |parameters| will typically be the contents -// of your bundle's Info.plist. +// Create a new BreakpadRef object and install it as an exception +// handler. The |parameters| will typically be the contents of your +// bundle's Info.plist. // // You can also specify these additional keys for customizable behavior: // Key: Value: @@ -127,6 +136,12 @@ typedef bool (*BreakpadFilterCallback)(int exception_type, // without any user intervention. // Defaults to NO // +// BREAKPAD_CONFIRM_TIMEOUT Number of seconds before the upload +// confirmation dialog will be automatically +// dismissed (cancelling the upload). +// Default: 300 seconds (min of 60). +// Specify 0 to prevent timeout. +// // BREAKPAD_SEND_AND_EXIT If true, the handler will exit after sending. // This will prevent any other handler (e.g., // CrashReporter) from getting the crash. @@ -149,19 +164,35 @@ typedef bool (*BreakpadFilterCallback)(int exception_type, // should be uploaded at crash time. // // BREAKPAD_REQUEST_COMMENTS If true, the message dialog will have a -// text box for the user to enter comments as -// well as a name and email address. +// text box for the user to enter comments. // Default: NO // -// The BREAKPAD_PRODUCT, BREAKPAD_VERSION, and BREAKPAD_URL are +// BREAKPAD_REQUEST_EMAIL If true and BREAKPAD_REQUEST_COMMENTS is also +// true, the message dialog will have a text +// box for the user to enter their email address. +// Default: NO +// +// BREAKPAD_SERVER_TYPE A parameter that tells Breakpad how to +// rewrite the upload parameters for a specific +// server type. The currently valid values are +// 'socorro' or 'google'. If you want to add +// other types, see the function in +// crash_report_sender.m that maps parameters to +// URL parameters. Defaults to 'google'. +// BREAKPAD_BUILD_ID A string parameter indicating build id. +// Optional. +//============================================================================= +// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are // required to have non-NULL values. By default, the BREAKPAD_PRODUCT // will be the CFBundleName and the BREAKPAD_VERSION will be the // CFBundleVersion when these keys are present in the bundle's -// Info.plist. If the BREAKPAD_PRODUCT or BREAKPAD_VERSION are -// ultimately undefined, BreakpadCreate() will fail. You have been -// warned. +// Info.plist, which is usually passed in to BreakpadCreate() as an +// NSDictionary (you could also pass in another dictionary that had +// the same keys configured). If the BREAKPAD_PRODUCT or +// BREAKPAD_VERSION are ultimately undefined, BreakpadCreate() will +// fail. You have been warned. // -// If you are running in a debugger, breakpad will not install, unless the +// If you are running in a debugger, Breakpad will not install, unless the // BREAKPAD_IGNORE_DEBUGGER envionment variable is set and/or non-zero. // // The BREAKPAD_SKIP_CONFIRM and BREAKPAD_SEND_AND_EXIT default @@ -173,6 +204,22 @@ typedef bool (*BreakpadFilterCallback)(int exception_type, // BREAKPAD_REPORTER_EXE_LOCATION allow you to specify custom paths // to the helper executables. // +//============================================================================= +// The following are NOT user-supplied but are documented here for +// completeness. They are calculated by Breakpad during initialization & +// crash-dump generation. +// +// BREAKPAD_PROCESS_START_TIME The time the process started. +// +// BREAKPAD_PROCESS_CRASH_TIME The time the process crashed. +// +// BREAKPAD_PROCESS_UP_TIME The total time the process has been running. +// This parameter is not set until the +// crash-dump-generation phase. +// +// BREAKPAD_LOGFILE_KEY_PREFIX Used to find out which parameters in the +// parameter dictionary correspond to log file +// paths. // Returns a new BreakpadRef object on success, NULL otherwise. BreakpadRef BreakpadCreate(NSDictionary *parameters); diff --git a/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.mm b/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.mm index 65678807dee..ed3d385eedb 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.mm +++ b/mozilla/camino/google-breakpad/src/client/mac/Framework/Breakpad.mm @@ -369,7 +369,6 @@ bool Breakpad::Initialize(NSDictionary *parameters) { new (gBreakpadAllocator->Allocate(sizeof(google_breakpad::ExceptionHandler))) google_breakpad::ExceptionHandler( Breakpad::ExceptionHandlerDirectCallback, this, true); - return true; } @@ -389,6 +388,10 @@ Breakpad::~Breakpad() { //============================================================================= bool Breakpad::ExtractParameters(NSDictionary *parameters) { NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults]; + NSString *skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM]; + NSString *sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT]; + + NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT]; NSString *version = [parameters objectForKey:@BREAKPAD_VERSION]; @@ -398,25 +401,25 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION]; NSString *reporterPathString = [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION]; - NSString *skipConfirm = [parameters objectForKey:@BREAKPAD_SKIP_CONFIRM]; - NSString *sendAndExit = [parameters objectForKey:@BREAKPAD_SEND_AND_EXIT]; + NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT]; NSArray *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES]; NSString *logFileTailSize = [parameters objectForKey:@BREAKPAD_LOGFILE_UPLOAD_SIZE]; NSString *reportEmail = [parameters objectForKey:@BREAKPAD_EMAIL]; NSString *requestUserText = [parameters objectForKey:@BREAKPAD_REQUEST_COMMENTS]; + NSString *requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL]; NSString *vendor = [parameters objectForKey:@BREAKPAD_VENDOR]; NSString *dumpSubdirectory = [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY]; - - // If these two are not already set(skipConfirm and sendAndExit can - // come from user defaults and take priority) + NSString *buildId = + [parameters objectForKey:@BREAKPAD_BUILD_ID]; + // These may have been set above as user prefs, which take priority. if (!skipConfirm) { - skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM]; + skipConfirm = [parameters objectForKey:@BREAKPAD_SKIP_CONFIRM]; } if (!sendAndExit) { - sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT]; + sendAndExit = [parameters objectForKey:@BREAKPAD_SEND_AND_EXIT]; } if (!product) @@ -431,6 +434,9 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { if (!interval) interval = @"3600"; + if (!timeout) + timeout = @"300"; + if (!logFileTailSize) logFileTailSize = @"200000"; @@ -528,12 +534,14 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { SimpleStringDictionary &dictionary = *config_params_; + dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]); dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]); dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]); dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]); dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]); dictionary.SetKeyValue(BREAKPAD_REPORT_INTERVAL, [interval UTF8String]); dictionary.SetKeyValue(BREAKPAD_SKIP_CONFIRM, [skipConfirm UTF8String]); + dictionary.SetKeyValue(BREAKPAD_CONFIRM_TIMEOUT, [timeout UTF8String]); dictionary.SetKeyValue(BREAKPAD_INSPECTOR_LOCATION, [inspectorPathString fileSystemRepresentation]); dictionary.SetKeyValue(BREAKPAD_REPORTER_EXE_LOCATION, @@ -542,16 +550,27 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { [logFileTailSize UTF8String]); dictionary.SetKeyValue(BREAKPAD_REQUEST_COMMENTS, [requestUserText UTF8String]); - dictionary.SetKeyValue(BREAKPAD_VENDOR, - [vendor UTF8String]); + dictionary.SetKeyValue(BREAKPAD_REQUEST_EMAIL, [requestEmail UTF8String]); + dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]); dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY, [dumpSubdirectory UTF8String]); + dictionary.SetKeyValue(BREAKPAD_BUILD_ID, + [buildId UTF8String]); + struct timeval tv; + gettimeofday(&tv, NULL); + char timeStartedString[32]; + sprintf(timeStartedString, "%d", tv.tv_sec); + dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, + timeStartedString); + if (logFilePaths) { char logFileKey[255]; for(unsigned int i = 0; i < [logFilePaths count]; i++) { sprintf(logFileKey,"%s%d", BREAKPAD_LOGFILE_KEY_PREFIX, i); - dictionary.SetKeyValue(logFileKey, [[logFilePaths objectAtIndex:i] fileSystemRepresentation]); + dictionary.SetKeyValue(logFileKey, + [[logFilePaths objectAtIndex:i] + fileSystemRepresentation]); } } diff --git a/mozilla/camino/google-breakpad/src/client/mac/Framework/OnDemandServer.mm b/mozilla/camino/google-breakpad/src/client/mac/Framework/OnDemandServer.mm index 32ac1faa89f..11b126c2eb3 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/Framework/OnDemandServer.mm +++ b/mozilla/camino/google-breakpad/src/client/mac/Framework/OnDemandServer.mm @@ -88,7 +88,7 @@ kern_return_t OnDemandServer::Initialize(const char *server_command, &service_port_); if (kr != KERN_SUCCESS) { - //PRINT_MACH_RESULT(kr, "bootstrap_create_service() : "); + PRINT_MACH_RESULT(kr, "bootstrap_create_service() : "); // perhaps the service has already been created - try to look it up kr = bootstrap_look_up(bootstrap_port, (char*)service_name, &service_port_); diff --git a/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.h b/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.h index 098c56e8a86..9ee5c48c4af 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.h +++ b/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.h @@ -171,6 +171,8 @@ class Inspector { kern_return_t SendAcknowledgement(); void LaunchReporter(const char *inConfigFilePath); + void SetCrashTimeParameters(); + mach_port_t service_rcv_port_; int exception_type_; diff --git a/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.mm b/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.mm index b147a860bc8..c61706caac4 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.mm +++ b/mozilla/camino/google-breakpad/src/client/mac/crash_generation/Inspector.mm @@ -160,8 +160,15 @@ void ConfigFile::WriteFile(const SimpleStringDictionary *configurationParameters sizeof(config_file_path_)); config_file_ = mkstemp(config_file_path_); - if (config_file_ == -1) + if (config_file_ == -1) { + DEBUGLOG(stderr, + "mkstemp(config_file_path_) == -1 (%s)\n", + strerror(errno)); return; + } + else { + DEBUGLOG(stderr, "Writing config file to (%s)\n", config_file_path_); + } has_created_file_ = true; @@ -177,6 +184,10 @@ void ConfigFile::WriteFile(const SimpleStringDictionary *configurationParameters SimpleStringDictionaryIterator iter(dictionary); while ((entry = iter.Next())) { + DEBUGLOG(stderr, + "config: (%s) -> (%s)\n", + entry->GetKey(), + entry->GetValue()); result = AppendConfigString(entry->GetKey(), entry->GetValue()); if (!result) @@ -321,15 +332,41 @@ kern_return_t Inspector::ReadMessages() { } //============================================================================= +// Sets keys in the parameters dictionary that are specific to process uptime. +// The two we set are process up time, and process crash time. +void Inspector::SetCrashTimeParameters() { + // Set process uptime parameter + struct timeval tv; + gettimeofday(&tv, NULL); + + char processUptimeString[32], processCrashtimeString[32]; + const char *processStartTimeString = + config_params_.GetValueForKey(BREAKPAD_PROCESS_START_TIME); + + // Set up time if we've received the start time. + if (processStartTimeString) { + time_t processStartTime = strtol(processStartTimeString, NULL, 10); + time_t processUptime = tv.tv_sec - processStartTime; + sprintf(processUptimeString, "%d", processUptime); + config_params_.SetKeyValue(BREAKPAD_PROCESS_UP_TIME, processUptimeString); + } + + sprintf(processCrashtimeString, "%d", tv.tv_sec); + config_params_.SetKeyValue(BREAKPAD_PROCESS_CRASH_TIME, + processCrashtimeString); +} + bool Inspector::InspectTask() { // keep the task quiet while we're looking at it task_suspend(remote_task_); + DEBUGLOG(stderr, "Suspsended Remote task\n"); NSString *minidumpDir; const char *minidumpDirectory = config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY); + SetCrashTimeParameters(); // If the client app has not specified a minidump directory, // use a default of Library// if (0 == strlen(minidumpDirectory)) { @@ -350,6 +387,9 @@ bool Inspector::InspectTask() { minidumpDir = [[NSString stringWithUTF8String:minidumpDirectory] stringByExpandingTildeInPath]; } + DEBUGLOG(stderr, + "Writing minidump to directory (%s)\n", + [minidumpDir UTF8String]); MinidumpLocation minidumpLocation(minidumpDir); @@ -368,14 +408,18 @@ bool Inspector::InspectTask() { NSString *minidumpPath = [NSString stringWithFormat:@"%s/%s.dmp", minidumpLocation.GetPath(), minidumpLocation.GetID()]; + DEBUGLOG(stderr, + "minidump path (%s)\n", + [minidumpPath UTF8String]); + bool result = generator.Write([minidumpPath fileSystemRepresentation]); - DEBUGLOG(stderr, "Inspector: finished writing minidump file: %s\n", - [minidumpPath fileSystemRepresentation]); + DEBUGLOG(stderr, "Wrote minidump - %s\n", result ? "OK" : "FAILED"); // let the task continue task_resume(remote_task_); + DEBUGLOG(stderr, "Resumed remote task\n"); return result; } diff --git a/mozilla/camino/google-breakpad/src/client/mac/handler/exception_handler_test.cc b/mozilla/camino/google-breakpad/src/client/mac/handler/exception_handler_test.cc index d84f1997bd8..e9d200f9892 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/handler/exception_handler_test.cc +++ b/mozilla/camino/google-breakpad/src/client/mac/handler/exception_handler_test.cc @@ -28,15 +28,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* -g++ -framework CoreFoundation -I../../.. \ - ../../minidump_file_writer.cc \ - ../../../common/convert_UTF.c \ - ../../../common/string_conversion.cc \ - ../../../common/mac/string_utilities.cc \ - exception_handler.cc \ - minidump_generator.cc \ - exception_handler_test.cc \ - -o exception_handler_test +g++ -framework CoreFoundation -I../../.. ../../minidump_file_writer.cc ../../../common/convert_UTF.c ../../../common/string_conversion.cc ../../../common/mac/string_utilities.cc exception_handler.cc minidump_generator.cc exception_handler_test.cc -o exception_handler_test -mmacosx-version-min=10.4 ../../../common/mac/file_id.cc dynamic_images.cc ../../../common/mac/macho_id.cc ../../../common/mac/macho_walker.cc -lcrypto ../../../common/mac/macho_utilities.cc */ #include diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib b/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib new file mode 100644 index 00000000000..ebc5ab40e73 --- /dev/null +++ b/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib @@ -0,0 +1,57 @@ + + + + + IBClasses + + + ACTIONS + + cancel + id + sendReport + id + showPrivacyPolicy + id + + CLASS + Reporter + LANGUAGE + ObjC + OUTLETS + + alertWindow_ + NSWindow + cancelButton_ + NSButton + commentMessage_ + NSTextField + dialogTitle_ + NSTextField + emailEntryField_ + NSView + emailLabel_ + NSTextField + emailMessage_ + NSTextField + emailSectionBox_ + NSBox + headerBox_ + NSBox + preEmailBox_ + NSBox + privacyLinkArrow_ + NSView + privacyLinkLabel_ + NSTextField + sendButton_ + NSButton + + SUPERCLASS + NSObject + + + IBVersion + 1 + + diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/info.nib b/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/info.nib similarity index 84% rename from mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/info.nib rename to mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/info.nib index 55565cda469..21bd6319e32 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/info.nib +++ b/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/info.nib @@ -3,9 +3,9 @@ IBFramework Version - 670 + 672 IBLastKnownRelativeProjectPath - ../../Breakpad.xcodeproj + ../Breakpad.xcodeproj IBOldestOS 5 IBOpenObjects @@ -13,7 +13,7 @@ 2 IBSystem Version - 9F33 + 9G55 targetFramework IBCocoaFramework diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib b/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib new file mode 100644 index 00000000000..d0cbd3f24e2 Binary files /dev/null and b/mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib differ diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/classes.nib b/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/classes.nib deleted file mode 100644 index 2636d457801..00000000000 --- a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/classes.nib +++ /dev/null @@ -1,33 +0,0 @@ - - - - - IBClasses - - - ACTIONS - - cancel - id - sendReport - id - showPrivacyPolicy - id - - CLASS - Reporter - LANGUAGE - ObjC - OUTLETS - - alertWindow - NSWindow - - SUPERCLASS - NSObject - - - IBVersion - 1 - - diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/keyedobjects.nib b/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/keyedobjects.nib deleted file mode 100644 index 50dff43de03..00000000000 Binary files a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Breakpad.nib/keyedobjects.nib and /dev/null differ diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Localizable.strings b/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Localizable.strings index aa2ca50303f..efc832acfbb 100644 Binary files a/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Localizable.strings and b/mozilla/camino/google-breakpad/src/client/mac/sender/English.lproj/Localizable.strings differ diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.h b/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.h index 76e6d3ea588..b31695382fc 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.h +++ b/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.h @@ -38,22 +38,46 @@ #define kClientIdPreferenceKey @"clientid" +extern NSString *const kGoogleServerType; +extern NSString *const kSocorroServerType; +extern NSString *const kDefaultServerType; @interface Reporter : NSObject { @public - IBOutlet NSWindow *alertWindow; // The alert window + IBOutlet NSWindow *alertWindow_; // The alert window - // Values bound in the XIB - NSString *headerMessage_; // Message notifying of the crash - NSString *reportMessage_; // Message explaining the crash report - NSString *commentsValue_; // Comments from the user - NSString *emailMessage_; // Message requesting user email - NSString *emailValue_; // Email from the user + // Grouping boxes used for resizing. + IBOutlet NSBox *headerBox_; + IBOutlet NSBox *preEmailBox_; + IBOutlet NSBox *emailSectionBox_; + // Localized elements (or things that need to be moved during localization). + IBOutlet NSTextField *dialogTitle_; + IBOutlet NSTextField *commentMessage_; + IBOutlet NSTextField *emailMessage_; + IBOutlet NSTextField *emailLabel_; + IBOutlet NSTextField *privacyLinkLabel_; + IBOutlet NSButton *sendButton_; + IBOutlet NSButton *cancelButton_; + IBOutlet NSView *emailEntryField_; + IBOutlet NSView *privacyLinkArrow_; + + // Text field bindings, for user input. + NSString *commentsValue_; // Comments from the user + NSString *emailValue_; // Email from the user @private - int configFile_; // File descriptor for config file - NSMutableDictionary *parameters_; // Key value pairs of data (STRONG) - NSData *minidumpContents_; // The data in the minidump (STRONG) - NSData *logFileData_; // An NSdata for the tar, bz2'd log file + int configFile_; // File descriptor for config file + NSMutableDictionary *parameters_; // Key value pairs of data (STRONG) + NSData *minidumpContents_; // The data in the minidump (STRONG) + NSData *logFileData_; // An NSdata for the tar, + // bz2'd log file + NSMutableDictionary *serverDictionary_; // The dictionary mapping a + // server type name to a + // dictionary of URL + // parameter names + NSMutableDictionary *socorroDictionary_; // The dictionary for + // Socorro + NSMutableDictionary *googleDictionary_; // The dictionary for + // Google } // Stops the modal panel with an NSAlertDefaultReturn value. This is the action @@ -62,28 +86,26 @@ // Stops the modal panel with an NSAlertAlternateReturn value. This is the // action invoked by the "Cancel" button. - (IBAction)cancel:(id)sender; -// Opens the Google Privacy Policy in the default web browser. +// Opens the Privacy Policy url in the default web browser. - (IBAction)showPrivacyPolicy:(id)sender; // Delegate methods for the NSTextField for comments. We want to capture the // Return key and use it to send the message when no text has been entered. // Otherwise, we want Return to add a carriage return to the comments field. -- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView - doCommandBySelector:(SEL)commandSelector; +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView + doCommandBySelector:(SEL)commandSelector; + +// Helper method to set HTTP parameters based on server type +- (BOOL)setPostParametersFromDictionary:(NSMutableDictionary *)crashParameters; // Accessors to make bindings work -- (NSString *)headerMessage; -- (void)setHeaderMessage:(NSString *)value; - -- (NSString *)reportMessage; -- (void)setReportMessage:(NSString *)value; - - (NSString *)commentsValue; - (void)setCommentsValue:(NSString *)value; -- (NSString *)emailMessage; -- (void)setEmailMessage:(NSString *)value; - - (NSString *)emailValue; - (void)setEmailValue:(NSString *)value; + +// Initialization helper to create dictionaries mapping Breakpad +// parameters to URL parameters +- (void)createServerParameterDictionaries; @end diff --git a/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.m b/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.m index 99f1eb10173..43d1da08aad 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.m +++ b/mozilla/camino/google-breakpad/src/client/mac/sender/crash_report_sender.m @@ -39,11 +39,122 @@ #import "crash_report_sender.h" #import "common/mac/GTMLogger.h" + #define kLastSubmission @"LastSubmission" const int kMinidumpFileLengthLimit = 800000; #define kApplePrefsSyncExcludeAllKey @"com.apple.PreferenceSync.ExcludeAllSyncKeys" +NSString *const kGoogleServerType = @"google"; +NSString *const kSocorroServerType = @"socorro"; +NSString *const kDefaultServerType = @"google"; + +#pragma mark - + +@interface NSView (ResizabilityExtentions) +// Shifts the view vertically by the given amount. +- (void)breakpad_shiftVertically:(float)offset; + +// Shifts the view horizontally by the given amount. +- (void)breakpad_shiftHorizontally:(float)offset; +@end + +@implementation NSView (ResizabilityExtentions) +- (void)breakpad_shiftVertically:(float)offset { + NSPoint origin = [self frame].origin; + origin.y += offset; + [self setFrameOrigin:origin]; +} + +- (void)breakpad_shiftHorizontally:(float)offset { + NSPoint origin = [self frame].origin; + origin.x += offset; + [self setFrameOrigin:origin]; +} +@end + +@interface NSWindow (ResizabilityExtentions) +// Adjusts the window height by heightDelta relative to its current height, +// keeping all the content at the same size. +- (void)breakpad_adjustHeight:(float)heightDelta; +@end + +@implementation NSWindow (ResizabilityExtentions) +- (void)breakpad_adjustHeight:(float)heightDelta { + [[self contentView] setAutoresizesSubviews:NO]; + + NSRect windowFrame = [self frame]; + windowFrame.size.height += heightDelta; + [self setFrame:windowFrame display:YES]; + // For some reason the content view is resizing, but not adjusting its origin, + // so correct it manually. + [[self contentView] setFrameOrigin:NSMakePoint(0, 0)]; + + [[self contentView] setAutoresizesSubviews:YES]; +} +@end + +@interface NSTextField (ResizabilityExtentions) +// Grows or shrinks the height of the field to the minimum required to show the +// current text, preserving the existing width and origin. +// Returns the change in height. +- (float)breakpad_adjustHeightToFit; + +// Grows or shrinks the width of the field to the minimum required to show the +// current text, preserving the existing height and origin. +// Returns the change in width. +- (float)breakpad_adjustWidthToFit; +@end + +@implementation NSTextField (ResizabilityExtentions) +- (float)breakpad_adjustHeightToFit { + NSRect oldFrame = [self frame]; + // sizeToFit will blow out the width rather than making the field taller, so + // we do it manually. + NSSize newSize = [[self cell] cellSizeForBounds:oldFrame]; + NSRect newFrame = NSMakeRect(oldFrame.origin.x, oldFrame.origin.y, + NSWidth(oldFrame), newSize.height); + [self setFrame:newFrame]; + + return newSize.height - NSHeight(oldFrame); +} + +- (float)breakpad_adjustWidthToFit { + NSRect oldFrame = [self frame]; + [self sizeToFit]; + return NSWidth([self frame]) - NSWidth(oldFrame); +} +@end + +@interface NSButton (ResizabilityExtentions) +// Resizes to fit the label using IB-style size-to-fit metrics and enforcing a +// minimum width of 70, while preserving the right edge location. +// Returns the change in width. +- (float)breakpad_smartSizeToFit; +@end + +@implementation NSButton (ResizabilityExtentions) +- (float)breakpad_smartSizeToFit { + NSRect oldFrame = [self frame]; + [self sizeToFit]; + NSRect newFrame = [self frame]; + // sizeToFit gives much worse results that IB's Size to Fit option. This is + // the amount of padding IB adds over a sizeToFit, empirically determined. + const float kExtraPaddingAmount = 12; + const float kMinButtonWidth = 70; // The default button size in IB. + newFrame.size.width = NSWidth(newFrame) + kExtraPaddingAmount; + if (NSWidth(newFrame) < kMinButtonWidth) + newFrame.size.width = kMinButtonWidth; + // Preserve the right edge location. + newFrame.origin.x = NSMaxX(oldFrame) - NSWidth(newFrame); + [self setFrame:newFrame]; + return NSWidth(newFrame) - NSWidth(oldFrame); +} +@end + +#pragma mark - + + @interface Reporter(PrivateMethods) + (uid_t)consoleUID; @@ -56,15 +167,57 @@ const int kMinidumpFileLengthLimit = 800000; - (BOOL)readMinidumpData; - (BOOL)readLogFileData; -- (BOOL)askUserPermissionToSend:(BOOL)shouldSubmitReport; -- (BOOL)shouldSubmitReport; +// Returns YES if it has been long enough since the last report that we should +// submit a report for this crash. +- (BOOL)reportIntervalElapsed; -// Run an alert window with the given timeout. Returns NSAlertButtonDefault if -// the timeout is exceeded. A timeout of 0 queues the message immediately in the -// modal run loop. +// Returns YES if we should send the report without asking the user first. +- (BOOL)shouldSubmitSilently; + +// Returns YES if we should ask the user to provide comments. +- (BOOL)shouldRequestComments; + +// Returns YES if we should ask the user to provide an email address. +- (BOOL)shouldRequestEmail; + +// Shows UI to the user to ask for permission to send and any extra information +// we've been instructed to request. Returns YES if the user allows the report +// to be sent. +- (BOOL)askUserPermissionToSend; + +// Returns the short description of the crash, suitable for use as a dialog +// title (e.g., "The application Foo has quit unexpectedly"). +- (NSString*)shortCrashDialogMessage; + +// Return explanatory text about the crash and the reporter, suitable for the +// body text of a dialog. +- (NSString*)explanatoryCrashDialogText; + +// Returns the amount of time the UI should be shown before timing out. +- (NSTimeInterval)messageTimeout; + +// Preps the comment-prompting alert window for display: +// * localizes all the elements +// * resizes and adjusts layout as necessary for localization +// * removes the email section if includeEmail is NO +- (void)configureAlertWindowIncludingEmail:(BOOL)includeEmail; + +// Rmevoes the email section of the dialog, adjusting the rest of the window +// as necessary. +- (void)removeEmailPrompt; + +// Run an alert window with the given timeout. Returns +// NSAlertButtonDefault if the timeout is exceeded. A timeout of 0 +// queues the message immediately in the modal run loop. - (int)runModalWindow:(NSWindow*)window withTimeout:(NSTimeInterval)timeout; +// Returns a unique client id (user-specific), creating a persistent +// one in the user defaults, if necessary. - (NSString*)clientID; + +// Returns a dictionary that can be used to map Breakpad parameter names to +// URL parameter names. +- (NSDictionary *)dictionaryForServerType:(NSString *)serverType; @end @implementation Reporter @@ -102,6 +255,8 @@ const int kMinidumpFileLengthLimit = 800000; [ud setBool:YES forKey:kApplePrefsSyncExcludeAllKey]; } + [self createServerParameterDictionaries]; + return self; } @@ -328,106 +483,39 @@ const int kMinidumpFileLengthLimit = 800000; } //============================================================================= -- (BOOL)askUserPermissionToSend:(BOOL)shouldSubmitReport { - // Send without confirmation - if ([[parameters_ objectForKey:@BREAKPAD_SKIP_CONFIRM] isEqualToString:@"YES"]) { - GTMLoggerDebug(@"Skipping confirmation and sending report"); - return YES; - } - - // Determine if we should create a text box for user feedback - BOOL shouldRequestComments = - [[parameters_ objectForKey:@BREAKPAD_REQUEST_COMMENTS] - isEqual:@"YES"]; - - NSString *display = [parameters_ objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; - - if (![display length]) - display = [parameters_ objectForKey:@BREAKPAD_PRODUCT]; - - NSString *vendor = [parameters_ objectForKey:@BREAKPAD_VENDOR]; - - if (![vendor length]) - vendor = @"Vendor not specified"; - - NSBundle *bundle = [NSBundle mainBundle]; - [self setHeaderMessage:[NSString stringWithFormat: - NSLocalizedStringFromTableInBundle(@"headerFmt", nil, - bundle, - @""), display]]; - NSString *defaultButtonTitle = nil; - NSString *otherButtonTitle = nil; - NSTimeInterval timeout = 60.0; // timeout value for the user notification - - // Get the localized alert strings - // If we're going to submit a report, prompt the user if this is okay. - // Otherwise, just let them know that the app crashed. - - if (shouldSubmitReport) { - NSString *msgFormat = NSLocalizedStringFromTableInBundle(@"msg", - nil, - bundle, @""); - - [self setReportMessage:[NSString stringWithFormat:msgFormat, vendor]]; - - defaultButtonTitle = NSLocalizedStringFromTableInBundle(@"sendReportButton", - nil, bundle, @""); - otherButtonTitle = NSLocalizedStringFromTableInBundle(@"cancelButton", nil, - bundle, @""); - - // Nominally use the report interval - timeout = [[parameters_ objectForKey:@BREAKPAD_REPORT_INTERVAL] - floatValue]; - } else { - [self setReportMessage:NSLocalizedStringFromTableInBundle(@"noSendMsg", nil, - bundle, @"")]; - defaultButtonTitle = NSLocalizedStringFromTableInBundle(@"noSendButton", - nil, bundle, @""); - timeout = 60.0; - } - // show the notification for at least one minute - if (timeout < 60.0) { - timeout = 60.0; - } - +- (BOOL)askUserPermissionToSend { // Initialize Cocoa, needed to display the alert NSApplicationLoad(); + // Get the timeout value for the notification. + NSTimeInterval timeout = [self messageTimeout]; + int buttonPressed = NSAlertAlternateReturn; - - if (shouldRequestComments) { + // Determine whether we should create a text box for user feedback. + if ([self shouldRequestComments]) { BOOL didLoadNib = [NSBundle loadNibNamed:@"Breakpad" owner:self]; - if (didLoadNib) { - // Append the request for comments to the |reportMessage| string. - NSString *commentsMessage = - NSLocalizedStringFromTableInBundle(@"commentsMsg", nil, bundle, @""); - [self setReportMessage:[NSString stringWithFormat:@"%@\n\n%@", - [self reportMessage], - commentsMessage]]; + if (!didLoadNib) { + return NO; + } - // Add the request for email address. - [self setEmailMessage: - NSLocalizedStringFromTableInBundle(@"emailMsg", nil, bundle, @"")]; + [self configureAlertWindowIncludingEmail:[self shouldRequestEmail]]; - // Run the alert - buttonPressed = [self runModalWindow:alertWindow withTimeout:timeout]; + buttonPressed = [self runModalWindow:alertWindow_ withTimeout:timeout]; - // Extract info from the user into the parameters_ dictionary - if ([self commentsValue]) { - [parameters_ setObject:[self commentsValue] - forKey:@BREAKPAD_COMMENTS]; - } - if ([self emailValue]) { - [parameters_ setObject:[self emailValue] - forKey:@BREAKPAD_EMAIL]; - } + // Extract info from the user into the parameters_ dictionary + if ([self commentsValue]) { + [parameters_ setObject:[self commentsValue] forKey:@BREAKPAD_COMMENTS]; + } + if ([self emailValue]) { + [parameters_ setObject:[self emailValue] forKey:@BREAKPAD_EMAIL]; } } else { // Create an alert panel to tell the user something happened - NSPanel* alert = NSGetAlertPanel([self headerMessage], - [self reportMessage], - defaultButtonTitle, - otherButtonTitle, nil); + NSPanel* alert = NSGetAlertPanel([self shortCrashDialogMessage], + [self explanatoryCrashDialogText], + NSLocalizedString(@"sendReportButton", @""), + NSLocalizedString(@"cancelButton", @""), + nil); // Pop the alert with an automatic timeout, and wait for the response buttonPressed = [self runModalWindow:alert withTimeout:timeout]; @@ -438,11 +526,65 @@ const int kMinidumpFileLengthLimit = 800000; return buttonPressed == NSAlertDefaultReturn; } +- (void)configureAlertWindowIncludingEmail:(BOOL)includeEmail { + // Swap in localized values, making size adjustments to impacted elements as + // we go. Remember that the origin is in the bottom left, so elements above + // "fall" as text areas are shrunk from their overly-large IB sizes. + + // Localize the header. No resizing needed, as it has plenty of room. + [dialogTitle_ setStringValue:[self shortCrashDialogMessage]]; + + // Localize the explanatory text field. + [commentMessage_ setStringValue:[NSString stringWithFormat:@"%@\n\n%@", + [self explanatoryCrashDialogText], + NSLocalizedString(@"commentsMsg", @"")]]; + float commentHeightDelta = [commentMessage_ breakpad_adjustHeightToFit]; + [headerBox_ breakpad_shiftVertically:commentHeightDelta]; + [alertWindow_ breakpad_adjustHeight:commentHeightDelta]; + + // Either localize the email explanation field or remove the whole email + // section depending on whether or not we are asking for email. + if (includeEmail) { + [emailMessage_ setStringValue:NSLocalizedString(@"emailMsg", @"")]; + float emailHeightDelta = [emailMessage_ breakpad_adjustHeightToFit]; + [preEmailBox_ breakpad_shiftVertically:emailHeightDelta]; + [alertWindow_ breakpad_adjustHeight:emailHeightDelta]; + } else { + [self removeEmailPrompt]; // Handles necessary resizing. + } + + // Localize the email label, and shift the associated text field. + [emailLabel_ setStringValue:NSLocalizedString(@"emailLabel", @"")]; + float emailLabelWidthDelta = [emailLabel_ breakpad_adjustWidthToFit]; + [emailEntryField_ breakpad_shiftHorizontally:emailLabelWidthDelta]; + + // Localize the privacy policy label, and keep it right-aligned to the arrow. + [privacyLinkLabel_ setStringValue:NSLocalizedString(@"privacyLabel", @"")]; + float privacyLabelWidthDelta = [privacyLinkLabel_ breakpad_adjustWidthToFit]; + [privacyLinkLabel_ breakpad_shiftHorizontally:(-privacyLabelWidthDelta)]; + + // Localize the buttons, and keep the cancel button at the right distance. + [sendButton_ setTitle:NSLocalizedString(@"sendReportButton", @"")]; + float sendButtonWidthDelta = [sendButton_ breakpad_smartSizeToFit]; + [cancelButton_ breakpad_shiftHorizontally:(-sendButtonWidthDelta)]; + [cancelButton_ setTitle:NSLocalizedString(@"cancelButton", @"")]; + [cancelButton_ breakpad_smartSizeToFit]; +} + +- (void)removeEmailPrompt { + [emailSectionBox_ setHidden:YES]; + float emailSectionHeight = NSHeight([emailSectionBox_ frame]); + [preEmailBox_ breakpad_shiftVertically:(-emailSectionHeight)]; + [alertWindow_ breakpad_adjustHeight:(-emailSectionHeight)]; +} + - (int)runModalWindow:(NSWindow*)window withTimeout:(NSTimeInterval)timeout { // Queue a |stopModal| message to be performed in |timeout| seconds. - [NSApp performSelector:@selector(stopModal) - withObject:nil - afterDelay:timeout]; + if (timeout > 0.001) { + [NSApp performSelector:@selector(stopModal) + withObject:nil + afterDelay:timeout]; + } // Run the window modally and wait for either a |stopModal| message or a // button click. @@ -459,7 +601,11 @@ const int kMinidumpFileLengthLimit = 800000; } - (IBAction)sendReport:(id)sender { - [alertWindow orderOut:self]; + // Force the text fields to end editing so text for the currently focused + // field will be commited. + [alertWindow_ makeFirstResponder:alertWindow_]; + + [alertWindow_ orderOut:self]; // Use NSAlertDefaultReturn so that the return value of |runModalWithWindow| // matches the AppKit function NSRunAlertPanel() [NSApp stopModalWithCode:NSAlertDefaultReturn]; @@ -468,7 +614,7 @@ const int kMinidumpFileLengthLimit = 800000; // UI Button Actions //============================================================================= - (IBAction)cancel:(id)sender { - [alertWindow orderOut:self]; + [alertWindow_ orderOut:self]; // Use NSAlertDefaultReturn so that the return value of |runModalWithWindow| // matches the AppKit function NSRunAlertPanel() [NSApp stopModalWithCode:NSAlertAlternateReturn]; @@ -477,15 +623,15 @@ const int kMinidumpFileLengthLimit = 800000; - (IBAction)showPrivacyPolicy:(id)sender { // Get the localized privacy policy URL and open it in the default browser. NSURL* privacyPolicyURL = - [NSURL URLWithString:NSLocalizedStringFromTableInBundle( - @"privacyPolicyURL", nil, [NSBundle mainBundle], @"")]; + [NSURL URLWithString:NSLocalizedString(@"privacyPolicyURL", @"")]; [[NSWorkspace sharedWorkspace] openURL:privacyPolicyURL]; } // Text Field Delegate Methods //============================================================================= -- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView - doCommandBySelector:(SEL)commandSelector { +- (BOOL) control:(NSControl*)control + textView:(NSTextView*)textView +doCommandBySelector:(SEL)commandSelector { BOOL result = NO; // If the user has entered text, don't end editing on "return" if (commandSelector == @selector(insertNewline:) @@ -496,29 +642,9 @@ const int kMinidumpFileLengthLimit = 800000; return result; } -// Accessors +#pragma mark Accessors +#pragma mark - //============================================================================= -- (NSString *)headerMessage { - return [[headerMessage_ retain] autorelease]; -} - -- (void)setHeaderMessage:(NSString *)value { - if (headerMessage_ != value) { - [headerMessage_ autorelease]; - headerMessage_ = [value copy]; - } -} - -- (NSString *)reportMessage { - return [[reportMessage_ retain] autorelease]; -} - -- (void)setReportMessage:(NSString *)value { - if (reportMessage_ != value) { - [reportMessage_ autorelease]; - reportMessage_ = [value copy]; - } -} - (NSString *)commentsValue { return [[commentsValue_ retain] autorelease]; @@ -526,35 +652,25 @@ const int kMinidumpFileLengthLimit = 800000; - (void)setCommentsValue:(NSString *)value { if (commentsValue_ != value) { - [commentsValue_ autorelease]; + [commentsValue_ release]; commentsValue_ = [value copy]; } } -- (NSString *)emailMessage { - return [[emailMessage_ retain] autorelease]; -} - -- (void)setEmailMessage:(NSString *)value { - if (emailMessage_ != value) { - [emailMessage_ autorelease]; - emailMessage_ = [value copy]; - } -} - - (NSString *)emailValue { return [[emailValue_ retain] autorelease]; } - (void)setEmailValue:(NSString *)value { if (emailValue_ != value) { - [emailValue_ autorelease]; + [emailValue_ release]; emailValue_ = [value copy]; } } +#pragma mark - //============================================================================= -- (BOOL)shouldSubmitReport { +- (BOOL)reportIntervalElapsed { float interval = [[parameters_ objectForKey:@BREAKPAD_REPORT_INTERVAL] floatValue]; NSString *program = [parameters_ objectForKey:@BREAKPAD_PRODUCT]; @@ -580,51 +696,127 @@ const int kMinidumpFileLengthLimit = 800000; return YES; } +- (BOOL)shouldSubmitSilently { + return [[parameters_ objectForKey:@BREAKPAD_SKIP_CONFIRM] + isEqualToString:@"YES"]; +} + +- (BOOL)shouldRequestComments { + return [[parameters_ objectForKey:@BREAKPAD_REQUEST_COMMENTS] + isEqualToString:@"YES"]; +} + +- (BOOL)shouldRequestEmail { + return [[parameters_ objectForKey:@BREAKPAD_REQUEST_EMAIL] + isEqualToString:@"YES"]; +} + +- (NSString*)shortCrashDialogMessage { + NSString *displayName = [parameters_ objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; + if (![displayName length]) + displayName = [parameters_ objectForKey:@BREAKPAD_PRODUCT]; + + return [NSString stringWithFormat:NSLocalizedString(@"headerFmt", @""), + displayName]; +} + +- (NSString*)explanatoryCrashDialogText { + NSString *vendor = [parameters_ objectForKey:@BREAKPAD_VENDOR]; + if (![vendor length]) + vendor = @"unknown vendor"; + + return [NSString stringWithFormat:NSLocalizedString(@"msgFmt", @""), vendor]; +} + +- (NSTimeInterval)messageTimeout { + // Get the timeout value for the notification. + NSTimeInterval timeout = [[parameters_ objectForKey:@BREAKPAD_CONFIRM_TIMEOUT] + floatValue]; + // Require a timeout of at least a minute (except 0, which means no timeout). + if (timeout > 0.001 && timeout < 60.0) { + timeout = 60.0; + } + return timeout; +} + +- (void)createServerParameterDictionaries { + serverDictionary_ = [[NSMutableDictionary alloc] init]; + socorroDictionary_ = [[NSMutableDictionary alloc] init]; + googleDictionary_ = [[NSMutableDictionary alloc] init]; + + [serverDictionary_ setObject:socorroDictionary_ forKey:kSocorroServerType]; + [serverDictionary_ setObject:googleDictionary_ forKey:kGoogleServerType]; + + [googleDictionary_ setObject:@"ptime" forKey:@BREAKPAD_PROCESS_UP_TIME]; + [googleDictionary_ setObject:@"email" forKey:@BREAKPAD_EMAIL]; + [googleDictionary_ setObject:@"comments" forKey:@BREAKPAD_COMMENTS]; + [googleDictionary_ setObject:@"prod" forKey:@BREAKPAD_PRODUCT]; + [googleDictionary_ setObject:@"ver" forKey:@BREAKPAD_VERSION]; + // TODO: just for testing, google's server doesn't support it + [googleDictionary_ setObject:@"buildid" forKey:@BREAKPAD_BUILD_ID]; + + [socorroDictionary_ setObject:@"Comments" forKey:@BREAKPAD_COMMENTS]; + [socorroDictionary_ setObject:@"CrashTime" + forKey:@BREAKPAD_PROCESS_CRASH_TIME]; + [socorroDictionary_ setObject:@"StartupTime" + forKey:@BREAKPAD_PROCESS_START_TIME]; + [socorroDictionary_ setObject:@"Version" + forKey:@BREAKPAD_VERSION]; + [socorroDictionary_ setObject:@"ProductName" + forKey:@BREAKPAD_PRODUCT]; + [socorroDictionary_ setObject:@"ProductName" + forKey:@BREAKPAD_PRODUCT]; + [socorroDictionary_ setObject:@"BuildID" + forKey:@BREAKPAD_BUILD_ID]; +} + +- (NSDictionary *)dictionaryForServerType:(NSString *)serverType { + if (serverType == nil || [serverType length] == 0) { + return [serverDictionary_ objectForKey:kDefaultServerType]; + } + return [serverDictionary_ objectForKey:serverType]; +} + +// Helper method to set HTTP parameters based on server type +- (BOOL)setPostParametersFromDictionary:(NSMutableDictionary *)crashParameters { + NSString *serverType = [parameters_ objectForKey:@BREAKPAD_SERVER_TYPE]; + NSDictionary *urlParameterNames = [self dictionaryForServerType:serverType]; + + id key; + NSEnumerator *enumerator = [parameters_ keyEnumerator]; + + while ((key = [enumerator nextObject])) { + // The key from parameters_ corresponds to a key in + // urlParameterNames. The value in parameters_ gets stored in + // crashParameters with a key that is the value in + // urlParameterNames. + + // For instance, if parameters_ has [PRODUCT_NAME => "FOOBAR"] and + // urlParameterNames has [PRODUCT_NAME => "pname"] the final HTTP + // URL parameter becomes [pname => "FOOBAR"]. + NSString *breakpadParameterName = (NSString *)key; + NSString *urlParameter = [urlParameterNames + objectForKey:breakpadParameterName]; + if (urlParameter) { + [crashParameters setObject:[parameters_ objectForKey:key] + forKey:urlParameter]; + } + } + return YES; +} + //============================================================================= - (void)report { NSURL *url = [NSURL URLWithString:[parameters_ objectForKey:@BREAKPAD_URL]]; HTTPMultipartUpload *upload = [[HTTPMultipartUpload alloc] initWithURL:url]; NSMutableDictionary *uploadParameters = [NSMutableDictionary dictionary]; - // Set the known parameters. This should be kept up to date with the - // parameters defined in the Breakpad.h list of parameters. The intent - // is so that if there's a parameter that's not in this list, we consider - // it to be a "user-defined" parameter and we'll upload it to the server. - NSSet *knownParameters = - [NSSet setWithObjects:@kReporterMinidumpDirectoryKey, - @kReporterMinidumpIDKey, @BREAKPAD_PRODUCT_DISPLAY, - @BREAKPAD_PRODUCT, @BREAKPAD_VERSION, @BREAKPAD_URL, - @BREAKPAD_REPORT_INTERVAL, @BREAKPAD_SKIP_CONFIRM, - @BREAKPAD_SEND_AND_EXIT, @BREAKPAD_REPORTER_EXE_LOCATION, - @BREAKPAD_INSPECTOR_LOCATION, @BREAKPAD_LOGFILES, - @BREAKPAD_LOGFILE_UPLOAD_SIZE, @BREAKPAD_EMAIL, - @BREAKPAD_REQUEST_COMMENTS, @BREAKPAD_COMMENTS, - @BREAKPAD_VENDOR, nil]; - - // Add parameters - [uploadParameters setObject:[parameters_ objectForKey:@BREAKPAD_PRODUCT] - forKey:@"prod"]; - [uploadParameters setObject:[parameters_ objectForKey:@BREAKPAD_VERSION] - forKey:@"ver"]; - - if ([parameters_ objectForKey:@BREAKPAD_EMAIL]) { - [uploadParameters setObject:[parameters_ objectForKey:@BREAKPAD_EMAIL] forKey:@"email"]; + if (![self setPostParametersFromDictionary:uploadParameters]) { + return; } - NSString* comments = [parameters_ objectForKey:@BREAKPAD_COMMENTS]; - if (comments != nil) { - [uploadParameters setObject:comments forKey:@"comments"]; - } - // Add any user parameters - NSArray *parameterKeys = [parameters_ allKeys]; - int keyCount = [parameterKeys count]; - for (int i = 0; i < keyCount; ++i) { - NSString *key = [parameterKeys objectAtIndex:i]; - if (![knownParameters containsObject:key] && - ![key hasPrefix:@BREAKPAD_LOGFILE_KEY_PREFIX]) - [uploadParameters setObject:[parameters_ objectForKey:key] forKey:key]; - } [upload setParameters:uploadParameters]; + // Add minidump file if (minidumpContents_) { [upload addFileContents:minidumpContents_ name:@"upload_file_minidump"]; @@ -657,13 +849,13 @@ const int kMinidumpFileLengthLimit = 800000; const char *dest = [destString fileSystemRepresentation]; if (rename(src, dest) == 0) { - fprintf(stderr, "Breakpad Reporter: Renamed %s to %s after successful " \ - "upload\n",src, dest); + GTMLoggerInfo(@"Breakpad Reporter: Renamed %s to %s after successful " \ + "upload",src, dest); } else { // can't rename - don't worry - it's not important for users - fprintf(stderr, "Breakpad Reporter: successful upload report ID = %s\n", - reportID ); + GTMLoggerDebug(@"Breakpad Reporter: successful upload report ID = %s\n", + reportID ); } [result release]; } @@ -691,13 +883,22 @@ const int kMinidumpFileLengthLimit = 800000; [parameters_ release]; [minidumpContents_ release]; [logFileData_ release]; + [googleDictionary_ release]; + [socorroDictionary_ release]; + [serverDictionary_ release]; [super dealloc]; } + @end //============================================================================= int main(int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +#if DEBUG + // Log to stderr in debug builds. + [GTMLogger setSharedLogger:[GTMLogger standardLoggerWithStderr]]; +#endif + GTMLoggerDebug(@"Reporter Launched, argc=%d", argc); // The expectation is that there will be one argument which is the path // to the configuration file if (argc != 2) { @@ -707,11 +908,20 @@ int main(int argc, const char *argv[]) { // Open the file before (potentially) switching to console user int configFile = open(argv[1], O_RDONLY, 0600); + if (configFile == -1) { + GTMLoggerDebug(@"Couldn't open config file %s - %s", + argv[1], + strerror(errno)); + } + // we want to avoid a build-up of old config files even if they // have been incorrectly written by the framework unlink(argv[1]); if (configFile == -1) { + GTMLoggerDebug(@"Couldn't unlink config file %s - %s", + argv[1], + strerror(errno)); exit(1); } @@ -719,6 +929,7 @@ int main(int argc, const char *argv[]) { // Gather the configuration data if (![reporter readConfigurationData]) { + GTMLoggerDebug(@"reporter readConfigurationData failed"); exit(1); } @@ -729,12 +940,17 @@ int main(int argc, const char *argv[]) { [reporter readLogFileData]; // only submit a report if we have not recently crashed in the past - BOOL shouldSubmitReport = [reporter shouldSubmitReport]; + BOOL shouldSubmitReport = [reporter reportIntervalElapsed]; BOOL okayToSend = NO; // ask user if we should send if (shouldSubmitReport) { - okayToSend = [reporter askUserPermissionToSend:shouldSubmitReport]; + if ([reporter shouldSubmitSilently]) { + GTMLoggerDebug(@"Skipping confirmation and sending report"); + okayToSend = YES; + } else { + okayToSend = [reporter askUserPermissionToSend]; + } } // If we're running as root, switch over to nobody @@ -742,23 +958,37 @@ int main(int argc, const char *argv[]) { struct passwd *pw = getpwnam("nobody"); // If we can't get a non-root uid, don't send the report - if (!pw) + if (!pw) { + GTMLoggerDebug(@"!pw - %s", strerror(errno)); exit(0); + } - if (setgid(pw->pw_gid) == -1) + if (setgid(pw->pw_gid) == -1) { + GTMLoggerDebug(@"setgid(pw->pw_gid) == -1 - %s", strerror(errno)); exit(0); + } - if (setuid(pw->pw_uid) == -1) + if (setuid(pw->pw_uid) == -1) { + GTMLoggerDebug(@"setuid(pw->pw_uid) == -1 - %s", strerror(errno)); exit(0); + } + } + else { + GTMLoggerDebug(@"getuid() !=0 || geteuid() != 0"); } if (okayToSend && shouldSubmitReport) { + GTMLoggerDebug(@"Sending Report"); [reporter report]; + GTMLoggerDebug(@"Report Sent!"); + } else { + GTMLoggerDebug(@"Not sending crash report okayToSend=%d, "\ + "shouldSubmitReport=%d", okayToSend, shouldSubmitReport); } + GTMLoggerDebug(@"Exiting with no errors"); // Cleanup [reporter release]; [pool release]; - return 0; } diff --git a/mozilla/camino/google-breakpad/src/client/mac/testapp/Info.plist b/mozilla/camino/google-breakpad/src/client/mac/testapp/Info.plist index 84755c5df76..2794c44b8d9 100644 --- a/mozilla/camino/google-breakpad/src/client/mac/testapp/Info.plist +++ b/mozilla/camino/google-breakpad/src/client/mac/testapp/Info.plist @@ -25,7 +25,7 @@ NSPrincipalClass NSApplication BreakpadProductDisplay - Google Breakpad Tester + Breakpad Tester BreakpadProduct Breakpad_Tester BreakpadVersion @@ -36,12 +36,12 @@ NO BreakpadSendAndExit YES + BreakpadRequestEmail + YES BreakpadRequestComments YES BreakpadVendor Foo Bar Corp, Incorporated, LTD, LLC - BreakpadMinidumpLocation - Breakpad Test Application/Crash Dumps LSUIElement 1 diff --git a/mozilla/camino/src/application/main.m b/mozilla/camino/src/application/main.m index 3cdb7636d17..370f6a2189b 100644 --- a/mozilla/camino/src/application/main.m +++ b/mozilla/camino/src/application/main.m @@ -71,13 +71,9 @@ int main(int argc, const char *argv[]) NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSDictionary* info = [[NSBundle mainBundle] infoDictionary]; BreakpadRef breakpad = BreakpadCreate(info); - // Add fields for Socorro - BreakpadSetKeyValue(breakpad, @"BuildID", [info valueForKey:@"MozillaBuildID"]); - BreakpadSetKeyValue(breakpad, @"ProductName", [info valueForKey:@"CFBundleName"]); - BreakpadSetKeyValue(breakpad, @"Version", [info valueForKey:@"CFBundleShortVersionString"]); - BreakpadSetKeyValue(breakpad, @"StartupTime", [NSString stringWithFormat:@"%ld", time(NULL)]); - // XXX lie for now, to get things working. - BreakpadSetKeyValue(breakpad, @"CrashTime", [NSString stringWithFormat:@"%ld", (time(NULL)+1)]); + // Breakpad uses CFBundleVersion, but we want our short version instead. + BreakpadSetKeyValue(breakpad, @BREAKPAD_VERSION, + [info valueForKey:@"CFBundleShortVersionString"]); [pool release]; SetupRuntimeOptions(argc, argv);