Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1195)

Unified Diff: components/crash/app/breakpad_mac.mm

Issue 1351923002: Revert of Turn components/crash into a layered component. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/crash/app/breakpad_mac.h ('k') | components/crash/app/breakpad_mac_stubs.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/crash/app/breakpad_mac.mm
diff --git a/components/crash/app/breakpad_mac.mm b/components/crash/app/breakpad_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..f435483fee4d643705940f18e37ee9cb21f8314c
--- /dev/null
+++ b/components/crash/app/breakpad_mac.mm
@@ -0,0 +1,286 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "components/crash/app/breakpad_mac.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#import <Foundation/Foundation.h>
+
+#include "base/auto_reset.h"
+#include "base/base_switches.h"
+#import "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#import "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#import "base/mac/scoped_nsautorelease_pool.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+#import "breakpad/src/client/mac/Framework/Breakpad.h"
+#include "components/crash/app/crash_reporter_client.h"
+
+using crash_reporter::GetCrashReporterClient;
+
+namespace breakpad {
+
+namespace {
+
+BreakpadRef gBreakpadRef = NULL;
+
+void SetCrashKeyValue(NSString* key, NSString* value) {
+ // Comment repeated from header to prevent confusion:
+ // IMPORTANT: On OS X, the key/value pairs are sent to the crash server
+ // out of bounds and not recorded on disk in the minidump, this means
+ // that if you look at the minidump file locally you won't see them!
+ if (gBreakpadRef == NULL) {
+ return;
+ }
+
+ BreakpadAddUploadParameter(gBreakpadRef, key, value);
+}
+
+void ClearCrashKeyValue(NSString* key) {
+ if (gBreakpadRef == NULL) {
+ return;
+ }
+
+ BreakpadRemoveUploadParameter(gBreakpadRef, key);
+}
+
+void SetCrashKeyValueImpl(const base::StringPiece& key,
+ const base::StringPiece& value) {
+ @autoreleasepool {
+ SetCrashKeyValue(base::SysUTF8ToNSString(key.as_string()),
+ base::SysUTF8ToNSString(value.as_string()));
+ }
+}
+
+void ClearCrashKeyValueImpl(const base::StringPiece& key) {
+ @autoreleasepool {
+ ClearCrashKeyValue(base::SysUTF8ToNSString(key.as_string()));
+ }
+}
+
+bool FatalMessageHandler(int severity, const char* file, int line,
+ size_t message_start, const std::string& str) {
+ // Do not handle non-FATAL.
+ if (severity != logging::LOG_FATAL)
+ return false;
+
+ // In case of OOM condition, this code could be reentered when
+ // constructing and storing the key. Using a static is not
+ // thread-safe, but if multiple threads are in the process of a
+ // fatal crash at the same time, this should work.
+ static bool guarded = false;
+ if (guarded)
+ return false;
+
+ base::AutoReset<bool> guard(&guarded, true);
+
+ // Only log last path component. This matches logging.cc.
+ if (file) {
+ const char* slash = strrchr(file, '/');
+ if (slash)
+ file = slash + 1;
+ }
+
+ NSString* fatal_key = @"LOG_FATAL";
+ NSString* fatal_value =
+ [NSString stringWithFormat:@"%s:%d: %s",
+ file, line, str.c_str() + message_start];
+ SetCrashKeyValue(fatal_key, fatal_value);
+
+ // Rather than including the code to force the crash here, allow the
+ // caller to do it.
+ return false;
+}
+
+// BreakpadGenerateAndSendReport() does not report the current
+// thread. This class can be used to spin up a thread to run it.
+class DumpHelper : public base::PlatformThread::Delegate {
+ public:
+ static void DumpWithoutCrashing() {
+ DumpHelper dumper;
+ base::PlatformThreadHandle handle;
+ if (base::PlatformThread::Create(0, &dumper, &handle)) {
+ // The entire point of this is to block so that the correct
+ // stack is logged.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ base::PlatformThread::Join(handle);
+ }
+ }
+
+ private:
+ DumpHelper() {}
+
+ void ThreadMain() override {
+ base::PlatformThread::SetName("CrDumpHelper");
+ BreakpadGenerateAndSendReport(gBreakpadRef);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DumpHelper);
+};
+
+void SIGABRTHandler(int signal) {
+ // The OSX abort() (link below) masks all signals for the process,
+ // and all except SIGABRT for the thread. SIGABRT will be masked
+ // when the SIGABRT is sent, which means at this point only SIGKILL
+ // and SIGSTOP can be delivered. Unmask others so that the code
+ // below crashes as desired.
+ //
+ // http://www.opensource.apple.com/source/Libc/Libc-825.26/stdlib/FreeBSD/abort.c
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, signal);
+ pthread_sigmask(SIG_SETMASK, &mask, NULL);
+
+ // Most interesting operations are not safe in a signal handler, just crash.
+ char* volatile death_ptr = NULL;
+ *death_ptr = '!';
+}
+
+} // namespace
+
+bool IsCrashReporterEnabled() {
+ return gBreakpadRef != NULL;
+}
+
+// Only called for a branded build of Chrome.app.
+void InitCrashReporter(const std::string& process_type) {
+ DCHECK(!gBreakpadRef);
+ base::mac::ScopedNSAutoreleasePool autorelease_pool;
+
+ // Check whether crash reporting should be enabled. If enterprise
+ // configuration management controls crash reporting, it takes precedence.
+ // Otherwise, check whether the user has consented to stats and crash
+ // reporting. The browser process can make this determination directly.
+ // Helper processes may not have access to the disk or to the same data as
+ // the browser process, so the browser passes the decision to them on the
+ // command line.
+ NSBundle* main_bundle = base::mac::FrameworkBundle();
+ bool is_browser = !base::mac::IsBackgroundOnlyProcess();
+ bool enable_breakpad = false;
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+ if (is_browser) {
+ // Since the configuration management infrastructure is possibly not
+ // initialized when this code runs, read the policy preference directly.
+ if (!GetCrashReporterClient()->ReportingIsEnforcedByPolicy(
+ &enable_breakpad)) {
+ // Controlled by the user. The crash reporter may be enabled by
+ // preference or through an environment variable, but the kDisableBreakpad
+ // switch overrides both.
+ enable_breakpad = GetCrashReporterClient()->GetCollectStatsConsent() ||
+ GetCrashReporterClient()->IsRunningUnattended();
+ enable_breakpad &= !command_line->HasSwitch(switches::kDisableBreakpad);
+ }
+ } else {
+ // This is a helper process, check the command line switch.
+ enable_breakpad = command_line->HasSwitch(switches::kEnableCrashReporter);
+ }
+
+ if (!enable_breakpad) {
+ VLOG_IF(1, is_browser) << "Breakpad disabled";
+ return;
+ }
+
+ // Tell Breakpad where crash_inspector and crash_report_sender are.
+ NSString* resource_path = [main_bundle resourcePath];
+ NSString *inspector_location =
+ [resource_path stringByAppendingPathComponent:@"crash_inspector"];
+ NSString *reporter_bundle_location =
+ [resource_path stringByAppendingPathComponent:@"crash_report_sender.app"];
+ NSString *reporter_location =
+ [[NSBundle bundleWithPath:reporter_bundle_location] executablePath];
+
+ if (!inspector_location || !reporter_location) {
+ VLOG_IF(1, is_browser && base::mac::AmIBundled()) << "Breakpad disabled";
+ return;
+ }
+
+ NSDictionary* info_dictionary = [main_bundle infoDictionary];
+ NSMutableDictionary *breakpad_config =
+ [[info_dictionary mutableCopy] autorelease];
+ [breakpad_config setObject:inspector_location
+ forKey:@BREAKPAD_INSPECTOR_LOCATION];
+ [breakpad_config setObject:reporter_location
+ forKey:@BREAKPAD_REPORTER_EXE_LOCATION];
+
+ // In the main application (the browser process), crashes can be passed to
+ // the system's Crash Reporter. This allows the system to notify the user
+ // when the application crashes, and provide the user with the option to
+ // restart it.
+ if (is_browser)
+ [breakpad_config setObject:@"NO" forKey:@BREAKPAD_SEND_AND_EXIT];
+
+ base::FilePath dir_crash_dumps;
+ GetCrashReporterClient()->GetCrashDumpLocation(&dir_crash_dumps);
+ [breakpad_config setObject:base::SysUTF8ToNSString(dir_crash_dumps.value())
+ forKey:@BREAKPAD_DUMP_DIRECTORY];
+
+ // Temporarily run Breakpad in-process on 10.10 and later because APIs that
+ // it depends on got broken (http://crbug.com/386208).
+ // This can catch crashes in the browser process only.
+ if (is_browser && base::mac::IsOSYosemiteOrLater()) {
+ [breakpad_config setObject:[NSNumber numberWithBool:YES]
+ forKey:@BREAKPAD_IN_PROCESS];
+ }
+
+ // Initialize Breakpad.
+ gBreakpadRef = BreakpadCreate(breakpad_config);
+ if (!gBreakpadRef) {
+ LOG_IF(ERROR, base::mac::AmIBundled()) << "Breakpad initialization failed";
+ return;
+ }
+
+ // Initialize the scoped crash key system.
+ base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValueImpl,
+ &ClearCrashKeyValueImpl);
+ GetCrashReporterClient()->RegisterCrashKeys();
+
+ // Set Breakpad metadata values. These values are added to Info.plist during
+ // the branded Google Chrome.app build.
+ SetCrashKeyValue(@"ver", [info_dictionary objectForKey:@BREAKPAD_VERSION]);
+ SetCrashKeyValue(@"prod", [info_dictionary objectForKey:@BREAKPAD_PRODUCT]);
+ SetCrashKeyValue(@"plat", @"OS X");
+
+ logging::SetLogMessageHandler(&FatalMessageHandler);
+ base::debug::SetDumpWithoutCrashingFunction(&DumpHelper::DumpWithoutCrashing);
+
+ // abort() sends SIGABRT, which breakpad does not intercept.
+ // Register a signal handler to crash in a way breakpad will
+ // intercept.
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = SIGABRTHandler;
+ CHECK(0 == sigaction(SIGABRT, &sigact, NULL));
+}
+
+void InitCrashProcessInfo(const std::string& process_type_switch) {
+ if (gBreakpadRef == NULL) {
+ return;
+ }
+
+ // Determine the process type.
+ NSString* process_type = @"browser";
+ if (!process_type_switch.empty()) {
+ process_type = base::SysUTF8ToNSString(process_type_switch);
+ }
+
+ // Store process type in crash dump.
+ SetCrashKeyValue(@"ptype", process_type);
+
+ NSString* pid_value =
+ [NSString stringWithFormat:@"%d", static_cast<unsigned int>(getpid())];
+ SetCrashKeyValue(@"pid", pid_value);
+}
+
+} // namespace breakpad
« no previous file with comments | « components/crash/app/breakpad_mac.h ('k') | components/crash/app/breakpad_mac_stubs.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698