Camino only - Bug 488513: Update breakpad to 335, and tweak our integration to account for the changes to the framework.
git-svn-id: svn://10.0.0.236/trunk@257079 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -2,12 +2,18 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BreakpadBuildID</key>
|
||||
<string>%PLATFORM_BUILD_ID%</string>
|
||||
<key>BreakpadConfirmTimeout</key>
|
||||
<string>0</string>
|
||||
<key>BreakpadReportInterval</key>
|
||||
<string>0</string>
|
||||
<key>BreakpadRequestComments</key>
|
||||
<string>YES</string>
|
||||
<key>BreakpadSendAndExit</key>
|
||||
<string>NO</string>
|
||||
<key>BreakpadServerType</key>
|
||||
<string>socorro</string>
|
||||
<key>BreakpadURL</key>
|
||||
<string>https://crash-reports.mozilla.com/submit</string>
|
||||
<key>BreakpadVendor</key>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = "<absolute>"; };
|
||||
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpad_Prefix.pch; path = Framework/Breakpad_Prefix.pch; sourceTree = "<group>"; };
|
||||
3329D4EC0FA16D820007BBC5 /* Breakpad.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = Breakpad.nib; path = sender/Breakpad.nib; sourceTree = "<group>"; };
|
||||
33880C7F0F9E097100817F82 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = crash_report_sender.icns; path = sender/crash_report_sender.icns; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
F9286B380F7EB25800A4DCC8 /* Inspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Inspector.h; path = crash_generation/Inspector.h; sourceTree = "<group>"; };
|
||||
F9286B390F7EB25800A4DCC8 /* InspectorMain.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = InspectorMain.mm; path = crash_generation/InspectorMain.mm; sourceTree = "<group>"; };
|
||||
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 = "<group>";
|
||||
@@ -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 = "<group>";
|
||||
};
|
||||
F9267CB10F844BDD00A827EC /* Breakpad.nib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
F9267CB20F844BDD00A827EC /* English */,
|
||||
);
|
||||
name = Breakpad.nib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F945849C0F280E3C009A47BF /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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/<kDefaultLibrarySubdirectory>/<Product Name>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 <pthread.h>
|
||||
|
||||
57
mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib
generated
Normal file
57
mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBClasses</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>cancel</key>
|
||||
<string>id</string>
|
||||
<key>sendReport</key>
|
||||
<string>id</string>
|
||||
<key>showPrivacyPolicy</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>Reporter</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>OUTLETS</key>
|
||||
<dict>
|
||||
<key>alertWindow_</key>
|
||||
<string>NSWindow</string>
|
||||
<key>cancelButton_</key>
|
||||
<string>NSButton</string>
|
||||
<key>commentMessage_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>dialogTitle_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>emailEntryField_</key>
|
||||
<string>NSView</string>
|
||||
<key>emailLabel_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>emailMessage_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>emailSectionBox_</key>
|
||||
<string>NSBox</string>
|
||||
<key>headerBox_</key>
|
||||
<string>NSBox</string>
|
||||
<key>preEmailBox_</key>
|
||||
<string>NSBox</string>
|
||||
<key>privacyLinkArrow_</key>
|
||||
<string>NSView</string>
|
||||
<key>privacyLinkLabel_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>sendButton_</key>
|
||||
<string>NSButton</string>
|
||||
</dict>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -3,9 +3,9 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>670</string>
|
||||
<string>672</string>
|
||||
<key>IBLastKnownRelativeProjectPath</key>
|
||||
<string>../../Breakpad.xcodeproj</string>
|
||||
<string>../Breakpad.xcodeproj</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>5</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
@@ -13,7 +13,7 @@
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>9F33</string>
|
||||
<string>9G55</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCocoaFramework</string>
|
||||
</dict>
|
||||
BIN
mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib
generated
Normal file
BIN
mozilla/camino/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib
generated
Normal file
Binary file not shown.
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBClasses</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>cancel</key>
|
||||
<string>id</string>
|
||||
<key>sendReport</key>
|
||||
<string>id</string>
|
||||
<key>showPrivacyPolicy</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>Reporter</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>OUTLETS</key>
|
||||
<dict>
|
||||
<key>alertWindow</key>
|
||||
<string>NSWindow</string>
|
||||
</dict>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>BreakpadProductDisplay</key>
|
||||
<string>Google Breakpad Tester</string>
|
||||
<string>Breakpad Tester</string>
|
||||
<key>BreakpadProduct</key>
|
||||
<string>Breakpad_Tester</string>
|
||||
<key>BreakpadVersion</key>
|
||||
@@ -36,12 +36,12 @@
|
||||
<string>NO</string>
|
||||
<key>BreakpadSendAndExit</key>
|
||||
<string>YES</string>
|
||||
<key>BreakpadRequestEmail</key>
|
||||
<string>YES</string>
|
||||
<key>BreakpadRequestComments</key>
|
||||
<string>YES</string>
|
||||
<key>BreakpadVendor</key>
|
||||
<string>Foo Bar Corp, Incorporated, LTD, LLC</string>
|
||||
<key>BreakpadMinidumpLocation</key>
|
||||
<string>Breakpad Test Application/Crash Dumps</string>
|
||||
<key>LSUIElement</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user