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

Side by Side Diff: components/breakpad/breakpad_mac.mm

Issue 31243002: Move Linux/Android breakpad implementation to breakpad component (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updates Created 7 years, 2 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « components/breakpad/breakpad_mac.h ('k') | components/breakpad/breakpad_mac_stubs.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "components/breakpad/breakpad_mac.h"
6
7 #include <CoreFoundation/CoreFoundation.h>
8 #import <Foundation/Foundation.h>
9
10 #include "base/auto_reset.h"
11 #include "base/base_switches.h"
12 #import "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/debug/crash_logging.h"
15 #include "base/file_util.h"
16 #include "base/files/file_path.h"
17 #import "base/logging.h"
18 #include "base/mac/bundle_locations.h"
19 #include "base/mac/mac_util.h"
20 #include "base/mac/scoped_cftyperef.h"
21 #import "base/mac/scoped_nsautorelease_pool.h"
22 #include "base/strings/sys_string_conversions.h"
23 #include "base/threading/platform_thread.h"
24 #include "base/threading/thread_restrictions.h"
25 #import "breakpad/src/client/mac/Framework/Breakpad.h"
26 #include "components/breakpad/breakpad_client.h"
27 #include "content/public/common/content_switches.h"
28
29 namespace breakpad {
30
31 namespace {
32
33 BreakpadRef gBreakpadRef = NULL;
34
35 void SetCrashKeyValue(NSString* key, NSString* value) {
36 // Comment repeated from header to prevent confusion:
37 // IMPORTANT: On OS X, the key/value pairs are sent to the crash server
38 // out of bounds and not recorded on disk in the minidump, this means
39 // that if you look at the minidump file locally you won't see them!
40 if (gBreakpadRef == NULL) {
41 return;
42 }
43
44 BreakpadAddUploadParameter(gBreakpadRef, key, value);
45 }
46
47 void ClearCrashKeyValue(NSString* key) {
48 if (gBreakpadRef == NULL) {
49 return;
50 }
51
52 BreakpadRemoveUploadParameter(gBreakpadRef, key);
53 }
54
55 void SetCrashKeyValueImpl(const base::StringPiece& key,
56 const base::StringPiece& value) {
57 SetCrashKeyValue(base::SysUTF8ToNSString(key.as_string()),
58 base::SysUTF8ToNSString(value.as_string()));
59 }
60
61 void ClearCrashKeyValueImpl(const base::StringPiece& key) {
62 ClearCrashKeyValue(base::SysUTF8ToNSString(key.as_string()));
63 }
64
65 bool FatalMessageHandler(int severity, const char* file, int line,
66 size_t message_start, const std::string& str) {
67 // Do not handle non-FATAL.
68 if (severity != logging::LOG_FATAL)
69 return false;
70
71 // In case of OOM condition, this code could be reentered when
72 // constructing and storing the key. Using a static is not
73 // thread-safe, but if multiple threads are in the process of a
74 // fatal crash at the same time, this should work.
75 static bool guarded = false;
76 if (guarded)
77 return false;
78
79 base::AutoReset<bool> guard(&guarded, true);
80
81 // Only log last path component. This matches logging.cc.
82 if (file) {
83 const char* slash = strrchr(file, '/');
84 if (slash)
85 file = slash + 1;
86 }
87
88 NSString* fatal_key = @"LOG_FATAL";
89 NSString* fatal_value =
90 [NSString stringWithFormat:@"%s:%d: %s",
91 file, line, str.c_str() + message_start];
92 SetCrashKeyValue(fatal_key, fatal_value);
93
94 // Rather than including the code to force the crash here, allow the
95 // caller to do it.
96 return false;
97 }
98
99 // BreakpadGenerateAndSendReport() does not report the current
100 // thread. This class can be used to spin up a thread to run it.
101 class DumpHelper : public base::PlatformThread::Delegate {
102 public:
103 static void DumpWithoutCrashing() {
104 DumpHelper dumper;
105 base::PlatformThreadHandle handle;
106 if (base::PlatformThread::Create(0, &dumper, &handle)) {
107 // The entire point of this is to block so that the correct
108 // stack is logged.
109 base::ThreadRestrictions::ScopedAllowIO allow_io;
110 base::PlatformThread::Join(handle);
111 }
112 }
113
114 private:
115 DumpHelper() {}
116
117 virtual void ThreadMain() OVERRIDE {
118 base::PlatformThread::SetName("CrDumpHelper");
119 BreakpadGenerateAndSendReport(gBreakpadRef);
120 }
121
122 DISALLOW_COPY_AND_ASSIGN(DumpHelper);
123 };
124
125 void SIGABRTHandler(int signal) {
126 // The OSX abort() (link below) masks all signals for the process,
127 // and all except SIGABRT for the thread. SIGABRT will be masked
128 // when the SIGABRT is sent, which means at this point only SIGKILL
129 // and SIGSTOP can be delivered. Unmask others so that the code
130 // below crashes as desired.
131 //
132 // http://www.opensource.apple.com/source/Libc/Libc-825.26/stdlib/FreeBSD/abor t.c
133 sigset_t mask;
134 sigemptyset(&mask);
135 sigaddset(&mask, signal);
136 pthread_sigmask(SIG_SETMASK, &mask, NULL);
137
138 // Most interesting operations are not safe in a signal handler, just crash.
139 char* volatile death_ptr = NULL;
140 *death_ptr = '!';
141 }
142
143 } // namespace
144
145 bool IsCrashReporterEnabled() {
146 return gBreakpadRef != NULL;
147 }
148
149 // Only called for a branded build of Chrome.app.
150 void InitCrashReporter() {
151 DCHECK(!gBreakpadRef);
152 base::mac::ScopedNSAutoreleasePool autorelease_pool;
153
154 // Check whether crash reporting should be enabled. If enterprise
155 // configuration management controls crash reporting, it takes precedence.
156 // Otherwise, check whether the user has consented to stats and crash
157 // reporting. The browser process can make this determination directly.
158 // Helper processes may not have access to the disk or to the same data as
159 // the browser process, so the browser passes the decision to them on the
160 // command line.
161 NSBundle* main_bundle = base::mac::FrameworkBundle();
162 bool is_browser = !base::mac::IsBackgroundOnlyProcess();
163 bool enable_breakpad = false;
164 CommandLine* command_line = CommandLine::ForCurrentProcess();
165
166 if (is_browser) {
167 // Since the configuration management infrastructure is possibly not
168 // initialized when this code runs, read the policy preference directly.
169 if (!GetBreakpadClient()->ReportingIsEnforcedByPolicy(&enable_breakpad)) {
170 // Controlled by the user. The crash reporter may be enabled by
171 // preference or through an environment variable, but the kDisableBreakpad
172 // switch overrides both.
173 enable_breakpad = GetBreakpadClient()->GetCollectStatsConsent() ||
174 GetBreakpadClient()->IsRunningUnattended();
175 enable_breakpad &= !command_line->HasSwitch(switches::kDisableBreakpad);
176 }
177 } else {
178 // This is a helper process, check the command line switch.
179 enable_breakpad = command_line->HasSwitch(switches::kEnableCrashReporter);
180 }
181
182 if (!enable_breakpad) {
183 VLOG_IF(1, is_browser) << "Breakpad disabled";
184 return;
185 }
186
187 // Tell Breakpad where crash_inspector and crash_report_sender are.
188 NSString* resource_path = [main_bundle resourcePath];
189 NSString *inspector_location =
190 [resource_path stringByAppendingPathComponent:@"crash_inspector"];
191 NSString *reporter_bundle_location =
192 [resource_path stringByAppendingPathComponent:@"crash_report_sender.app"];
193 NSString *reporter_location =
194 [[NSBundle bundleWithPath:reporter_bundle_location] executablePath];
195
196 if (!inspector_location || !reporter_location) {
197 VLOG_IF(1, is_browser && base::mac::AmIBundled()) << "Breakpad disabled";
198 return;
199 }
200
201 NSDictionary* info_dictionary = [main_bundle infoDictionary];
202 NSMutableDictionary *breakpad_config =
203 [[info_dictionary mutableCopy] autorelease];
204 [breakpad_config setObject:inspector_location
205 forKey:@BREAKPAD_INSPECTOR_LOCATION];
206 [breakpad_config setObject:reporter_location
207 forKey:@BREAKPAD_REPORTER_EXE_LOCATION];
208
209 // In the main application (the browser process), crashes can be passed to
210 // the system's Crash Reporter. This allows the system to notify the user
211 // when the application crashes, and provide the user with the option to
212 // restart it.
213 if (is_browser)
214 [breakpad_config setObject:@"NO" forKey:@BREAKPAD_SEND_AND_EXIT];
215
216 base::FilePath dir_crash_dumps;
217 GetBreakpadClient()->GetCrashDumpLocation(&dir_crash_dumps);
218 [breakpad_config setObject:base::SysUTF8ToNSString(dir_crash_dumps.value())
219 forKey:@BREAKPAD_DUMP_DIRECTORY];
220
221 // Initialize Breakpad.
222 gBreakpadRef = BreakpadCreate(breakpad_config);
223 if (!gBreakpadRef) {
224 LOG_IF(ERROR, base::mac::AmIBundled()) << "Breakpad initializaiton failed";
225 return;
226 }
227
228 // Initialize the scoped crash key system.
229 base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValueImpl,
230 &ClearCrashKeyValueImpl);
231 GetBreakpadClient()->RegisterCrashKeys();
232
233 // Set Breakpad metadata values. These values are added to Info.plist during
234 // the branded Google Chrome.app build.
235 SetCrashKeyValue(@"ver", [info_dictionary objectForKey:@BREAKPAD_VERSION]);
236 SetCrashKeyValue(@"prod", [info_dictionary objectForKey:@BREAKPAD_PRODUCT]);
237 SetCrashKeyValue(@"plat", @"OS X");
238
239 if (!is_browser) {
240 // Get the guid from the command line switch.
241 std::string guid =
242 command_line->GetSwitchValueASCII(switches::kEnableCrashReporter);
243 GetBreakpadClient()->SetClientID(guid);
244 }
245
246 logging::SetLogMessageHandler(&FatalMessageHandler);
247 GetBreakpadClient()->SetDumpWithoutCrashingFunction(
248 &DumpHelper::DumpWithoutCrashing);
249
250 // abort() sends SIGABRT, which breakpad does not intercept.
251 // Register a signal handler to crash in a way breakpad will
252 // intercept.
253 struct sigaction sigact;
254 memset(&sigact, 0, sizeof(sigact));
255 sigact.sa_handler = SIGABRTHandler;
256 CHECK(0 == sigaction(SIGABRT, &sigact, NULL));
257 }
258
259 void InitCrashProcessInfo() {
260 if (gBreakpadRef == NULL) {
261 return;
262 }
263
264 // Determine the process type.
265 NSString* process_type = @"browser";
266 std::string process_type_switch =
267 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
268 switches::kProcessType);
269 if (!process_type_switch.empty()) {
270 process_type = base::SysUTF8ToNSString(process_type_switch);
271 }
272
273 GetBreakpadClient()->InstallAdditionalFilters(gBreakpadRef);
274
275 // Store process type in crash dump.
276 SetCrashKeyValue(@"ptype", process_type);
277 }
278
279 } // namespace breakpad
OLDNEW
« no previous file with comments | « components/breakpad/breakpad_mac.h ('k') | components/breakpad/breakpad_mac_stubs.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698