1 // Copyright (c) 2011 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.
5 #include "chrome/app/breakpad_win.h"
14 #include "base/base_switches.h"
15 #include "base/command_line.h"
16 #include "base/environment.h"
17 #include "base/file_util.h"
18 #include "base/file_version_info.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/string_split.h"
21 #include "base/string_util.h"
22 #include "base/utf_string_conversions.h"
23 #include "base/win/registry.h"
24 #include "base/win/win_util.h"
25 #include "breakpad/src/client/windows/handler/exception_handler.h"
26 #include "chrome/app/hard_error_handler_win.h"
27 #include "chrome/common/child_process_logging.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/env_vars.h"
30 #include "chrome/installer/util/google_chrome_sxs_distribution.h"
31 #include "chrome/installer/util/google_update_settings.h"
32 #include "chrome/installer/util/install_util.h"
33 #include "content/common/result_codes.h"
34 #include "policy/policy_constants.h"
38 // Minidump with stacks, PEB, TEB, and unloaded module list.
39 const MINIDUMP_TYPE kSmallDumpType
= static_cast<MINIDUMP_TYPE
>(
40 MiniDumpWithProcessThreadData
| // Get PEB and TEB.
41 MiniDumpWithUnloadedModules
); // Get unloaded modules when available.
43 // Minidump with all of the above, plus memory referenced from stack.
44 const MINIDUMP_TYPE kLargerDumpType
= static_cast<MINIDUMP_TYPE
>(
45 MiniDumpWithProcessThreadData
| // Get PEB and TEB.
46 MiniDumpWithUnloadedModules
| // Get unloaded modules when available.
47 MiniDumpWithIndirectlyReferencedMemory
); // Get memory referenced by stack.
49 // Large dump with all process memory.
50 const MINIDUMP_TYPE kFullDumpType
= static_cast<MINIDUMP_TYPE
>(
51 MiniDumpWithFullMemory
| // Full memory from process.
52 MiniDumpWithProcessThreadData
| // Get PEB and TEB.
53 MiniDumpWithHandleData
| // Get all handle information.
54 MiniDumpWithUnloadedModules
); // Get unloaded modules when available.
56 const wchar_t kGoogleUpdatePipeName
[] = L
"\\\\.\\pipe\\GoogleCrashServices\\";
57 const wchar_t kChromePipeName
[] = L
"\\\\.\\pipe\\ChromeCrashServices";
59 // This is the well known SID for the system principal.
60 const wchar_t kSystemPrincipalSid
[] =L
"S-1-5-18";
62 google_breakpad::ExceptionHandler
* g_breakpad
= NULL
;
64 // A pointer to the custom entries that we send in the event of a crash. We need
65 // this pointer, along with the offsets into it below, so that we can keep the
66 // data updated as the state of the browser changes.
67 static std::vector
<google_breakpad::CustomInfoEntry
>* g_custom_entries
= NULL
;
68 static size_t g_url_chunks_offset
;
69 static size_t g_num_of_extensions_offset
;
70 static size_t g_extension_ids_offset
;
71 static size_t g_client_id_offset
;
72 static size_t g_gpu_info_offset
;
73 static size_t g_num_of_views_offset
;
75 // Dumps the current process memory.
76 extern "C" void __declspec(dllexport
) __cdecl
DumpProcess() {
78 g_breakpad
->WriteMinidump();
81 // Reduces the size of the string |str| to a max of 64 chars. Required because
82 // breakpad's CustomInfoEntry raises an invalid_parameter error if the string
83 // we want to set is longer.
84 std::wstring
TrimToBreakpadMax(const std::wstring
& str
) {
85 std::wstring
shorter(str
);
86 return shorter
.substr(0,
87 google_breakpad::CustomInfoEntry::kValueMaxLength
- 1);
90 // Returns the custom info structure based on the dll in parameter and the
92 google_breakpad::CustomClientInfo
* GetCustomInfo(const std::wstring
& dll_path
,
93 const std::wstring
& type
) {
94 scoped_ptr
<FileVersionInfo
>
95 version_info(FileVersionInfo::CreateFileVersionInfo(FilePath(dll_path
)));
97 std::wstring version
, product
;
98 if (version_info
.get()) {
99 // Get the information from the file.
100 version
= version_info
->product_version();
101 if (!version_info
->is_official_build())
102 version
.append(L
"-devel");
104 const CommandLine
& command
= *CommandLine::ForCurrentProcess();
105 if (command
.HasSwitch(switches::kChromeFrame
)) {
106 product
= L
"ChromeFrame";
108 product
= version_info
->product_short_name();
111 // No version info found. Make up the values.
113 version
= L
"0.0.0.0-devel";
116 // We only expect this method to be called once per process.
117 DCHECK(!g_custom_entries
);
118 g_custom_entries
= new std::vector
<google_breakpad::CustomInfoEntry
>;
120 // Common g_custom_entries.
121 g_custom_entries
->push_back(
122 google_breakpad::CustomInfoEntry(L
"ver", version
.c_str()));
123 g_custom_entries
->push_back(
124 google_breakpad::CustomInfoEntry(L
"prod", product
.c_str()));
125 g_custom_entries
->push_back(
126 google_breakpad::CustomInfoEntry(L
"plat", L
"Win32"));
127 g_custom_entries
->push_back(
128 google_breakpad::CustomInfoEntry(L
"ptype", type
.c_str()));
130 g_num_of_extensions_offset
= g_custom_entries
->size();
131 g_custom_entries
->push_back(
132 google_breakpad::CustomInfoEntry(L
"num-extensions", L
"N/A"));
134 g_extension_ids_offset
= g_custom_entries
->size();
135 for (int i
= 0; i
< kMaxReportedActiveExtensions
; ++i
) {
136 g_custom_entries
->push_back(google_breakpad::CustomInfoEntry(
137 StringPrintf(L
"extension-%i", i
+ 1).c_str(), L
""));
140 // Add empty values for the gpu_info. We'll put the actual values
141 // when we collect them at this location.
142 g_gpu_info_offset
= g_custom_entries
->size();
143 g_custom_entries
->push_back(
144 google_breakpad::CustomInfoEntry(L
"gpu-venid", L
""));
145 g_custom_entries
->push_back(
146 google_breakpad::CustomInfoEntry(L
"gpu-devid", L
""));
147 g_custom_entries
->push_back(
148 google_breakpad::CustomInfoEntry(L
"gpu-driver", L
""));
149 g_custom_entries
->push_back(
150 google_breakpad::CustomInfoEntry(L
"gpu-psver", L
""));
151 g_custom_entries
->push_back(
152 google_breakpad::CustomInfoEntry(L
"gpu-vsver", L
""));
154 // Read the id from registry. If reporting has never been enabled
155 // the result will be empty string. Its OK since when user enables reporting
156 // we will insert the new value at this location.
158 GoogleUpdateSettings::GetMetricsId(&guid
);
159 g_client_id_offset
= g_custom_entries
->size();
160 g_custom_entries
->push_back(
161 google_breakpad::CustomInfoEntry(L
"guid", guid
.c_str()));
163 if (type
== L
"renderer" || type
== L
"plugin" || type
== L
"gpu-process") {
164 g_num_of_views_offset
= g_custom_entries
->size();
165 g_custom_entries
->push_back(
166 google_breakpad::CustomInfoEntry(L
"num-views", L
""));
167 // Create entries for the URL. Currently we only allow each chunk to be 64
168 // characters, which isn't enough for a URL. As a hack we create 8 entries
169 // and split the URL across the g_custom_entries.
170 g_url_chunks_offset
= g_custom_entries
->size();
171 for (int i
= 0; i
< kMaxUrlChunks
; ++i
) {
172 g_custom_entries
->push_back(google_breakpad::CustomInfoEntry(
173 StringPrintf(L
"url-chunk-%i", i
+ 1).c_str(), L
""));
176 g_custom_entries
->push_back(
177 google_breakpad::CustomInfoEntry(L
"num-views", L
"N/A"));
179 // Browser-specific g_custom_entries.
180 google_breakpad::CustomInfoEntry
switch1(L
"switch-1", L
"");
181 google_breakpad::CustomInfoEntry
switch2(L
"switch-2", L
"");
183 // Get the first two command line switches if they exist. The CommandLine
184 // class does not allow to enumerate the switches so we do it by hand.
186 wchar_t** args
= ::CommandLineToArgvW(::GetCommandLineW(), &num_args
);
189 switch1
.set_value(TrimToBreakpadMax(args
[1]).c_str());
191 switch2
.set_value(TrimToBreakpadMax(args
[2]).c_str());
192 // The caller must free the memory allocated for |args|.
196 g_custom_entries
->push_back(switch1
);
197 g_custom_entries
->push_back(switch2
);
200 static google_breakpad::CustomClientInfo custom_client_info
;
201 custom_client_info
.entries
= &g_custom_entries
->front();
202 custom_client_info
.count
= g_custom_entries
->size();
204 return &custom_client_info
;
207 // Contains the information needed by the worker thread.
208 struct CrashReporterInfo
{
209 google_breakpad::CustomClientInfo
* custom_info
;
210 std::wstring dll_path
;
211 std::wstring process_type
;
214 // This callback is executed when the browser process has crashed, after
215 // the crash dump has been created. We need to minimize the amount of work
216 // done here since we have potentially corrupted process. Our job is to
217 // spawn another instance of chrome which will show a 'chrome has crashed'
218 // dialog. This code needs to live in the exe and thus has no access to
219 // facilities such as the i18n helpers.
220 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
221 EXCEPTION_POINTERS
* ex_info
,
222 MDRawAssertionInfo
*, bool) {
223 // If the exception is because there was a problem loading a delay-loaded
224 // module, then show the user a dialog explaining the problem and then exit.
225 if (DelayLoadFailureExceptionMessageBox(ex_info
))
228 // We set CHROME_CRASHED env var. If the CHROME_RESTART is present.
229 // This signals the child process to show the 'chrome has crashed' dialog.
230 scoped_ptr
<base::Environment
> env(base::Environment::Create());
231 if (!env
->HasVar(env_vars::kRestartInfo
)) {
234 env
->SetVar(env_vars::kShowRestart
, "1");
235 // Now we just start chrome browser with the same command line.
236 STARTUPINFOW si
= {sizeof(si
)};
237 PROCESS_INFORMATION pi
;
238 if (::CreateProcessW(NULL
, ::GetCommandLineW(), NULL
, NULL
, FALSE
,
239 CREATE_UNICODE_ENVIRONMENT
, NULL
, NULL
, &si
, &pi
)) {
240 ::CloseHandle(pi
.hProcess
);
241 ::CloseHandle(pi
.hThread
);
243 // After this return we will be terminated. The actual return value is
248 // flag to indicate that we are already handling an exception.
249 volatile LONG handling_exception
= 0;
251 // This callback is executed when the Chrome process has crashed and *before*
252 // the crash dump is created. To prevent duplicate crash reports we
253 // make every thread calling this method, except the very first one,
255 bool FilterCallback(void*, EXCEPTION_POINTERS
*, MDRawAssertionInfo
*) {
256 // Capture every thread except the first one in the sleep. We don't
257 // want multiple threads to concurrently report exceptions.
258 if (::InterlockedCompareExchange(&handling_exception
, 1, 0) == 1) {
264 // Previous unhandled filter. Will be called if not null when we
265 // intercept a crash.
266 LPTOP_LEVEL_EXCEPTION_FILTER previous_filter
= NULL
;
268 // Exception filter used when breakpad is not enabled. We just display
269 // the "Do you want to restart" message and then we call the previous filter.
270 long WINAPI
ChromeExceptionFilter(EXCEPTION_POINTERS
* info
) {
271 DumpDoneCallback(NULL
, NULL
, NULL
, info
, NULL
, false);
274 return previous_filter(info
);
276 return EXCEPTION_EXECUTE_HANDLER
;
279 // Exception filter for the service process used when breakpad is not enabled.
280 // We just display the "Do you want to restart" message and then die
281 // (without calling the previous filter).
282 long WINAPI
ServiceExceptionFilter(EXCEPTION_POINTERS
* info
) {
283 DumpDoneCallback(NULL
, NULL
, NULL
, info
, NULL
, false);
284 return EXCEPTION_EXECUTE_HANDLER
;
287 extern "C" void __declspec(dllexport
) __cdecl
SetActiveURL(
288 const wchar_t* url_cstring
) {
291 if (!g_custom_entries
)
294 std::wstring
url(url_cstring
);
295 size_t chunk_index
= 0;
296 size_t url_size
= url
.size();
298 // Split the url across all the chunks.
299 for (size_t url_offset
= 0;
300 chunk_index
< kMaxUrlChunks
&& url_offset
< url_size
; ++chunk_index
) {
301 size_t current_chunk_size
= std::min(url_size
- url_offset
,
303 google_breakpad::CustomInfoEntry::kValueMaxLength
- 1));
305 wchar_t* entry_value
=
306 (*g_custom_entries
)[g_url_chunks_offset
+ chunk_index
].value
;
307 url
._Copy_s(entry_value
,
308 google_breakpad::CustomInfoEntry::kValueMaxLength
,
309 current_chunk_size
, url_offset
);
310 entry_value
[current_chunk_size
] = L
'\0';
311 url_offset
+= current_chunk_size
;
314 // And null terminate any unneeded chunks.
315 for (; chunk_index
< kMaxUrlChunks
; ++chunk_index
)
316 (*g_custom_entries
)[g_url_chunks_offset
+ chunk_index
].value
[0] = L
'\0';
319 extern "C" void __declspec(dllexport
) __cdecl
SetClientId(
320 const wchar_t* client_id
) {
321 if (client_id
== NULL
)
324 if (!g_custom_entries
)
327 wcscpy_s((*g_custom_entries
)[g_client_id_offset
].value
,
328 google_breakpad::CustomInfoEntry::kValueMaxLength
,
332 static void SetIntegerValue(size_t offset
, int value
) {
333 if (!g_custom_entries
)
336 wcscpy_s((*g_custom_entries
)[offset
].value
,
337 google_breakpad::CustomInfoEntry::kValueMaxLength
,
338 StringPrintf(L
"%d", value
).c_str());
341 extern "C" void __declspec(dllexport
) __cdecl
SetNumberOfExtensions(
342 int number_of_extensions
) {
343 SetIntegerValue(g_num_of_extensions_offset
, number_of_extensions
);
346 extern "C" void __declspec(dllexport
) __cdecl
SetExtensionID(
347 int index
, const wchar_t* id
) {
349 DCHECK(index
< kMaxReportedActiveExtensions
);
351 if (!g_custom_entries
)
354 wcscpy_s((*g_custom_entries
)[g_extension_ids_offset
+ index
].value
,
355 google_breakpad::CustomInfoEntry::kValueMaxLength
,
359 extern "C" void __declspec(dllexport
) __cdecl
SetGpuInfo(
360 const wchar_t* vendor_id
, const wchar_t* device_id
,
361 const wchar_t* driver_version
, const wchar_t* pixel_shader_version
,
362 const wchar_t* vertex_shader_version
) {
363 if (!g_custom_entries
)
366 wcscpy_s((*g_custom_entries
)[g_gpu_info_offset
].value
,
367 google_breakpad::CustomInfoEntry::kValueMaxLength
,
369 wcscpy_s((*g_custom_entries
)[g_gpu_info_offset
+1].value
,
370 google_breakpad::CustomInfoEntry::kValueMaxLength
,
372 wcscpy_s((*g_custom_entries
)[g_gpu_info_offset
+2].value
,
373 google_breakpad::CustomInfoEntry::kValueMaxLength
,
375 wcscpy_s((*g_custom_entries
)[g_gpu_info_offset
+3].value
,
376 google_breakpad::CustomInfoEntry::kValueMaxLength
,
377 pixel_shader_version
);
378 wcscpy_s((*g_custom_entries
)[g_gpu_info_offset
+4].value
,
379 google_breakpad::CustomInfoEntry::kValueMaxLength
,
380 vertex_shader_version
);
383 extern "C" void __declspec(dllexport
) __cdecl
SetNumberOfViews(
384 int number_of_views
) {
385 SetIntegerValue(g_num_of_views_offset
, number_of_views
);
390 bool WrapMessageBoxWithSEH(const wchar_t* text
, const wchar_t* caption
,
391 UINT flags
, bool* exit_now
) {
392 // We wrap the call to MessageBoxW with a SEH handler because it some
393 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
394 // uncontrollably here. Being this a best effort deal we better go away.
396 *exit_now
= (IDOK
!= ::MessageBoxW(NULL
, text
, caption
, flags
));
397 } __except(EXCEPTION_EXECUTE_HANDLER
) {
398 // Its not safe to continue executing, exit silently here.
399 ::ExitProcess(ResultCodes::RESPAWN_FAILED
);
405 // This function is executed by the child process that DumpDoneCallback()
406 // spawned and basically just shows the 'chrome has crashed' dialog if
407 // the CHROME_CRASHED environment variable is present.
408 bool ShowRestartDialogIfCrashed(bool* exit_now
) {
409 if (!::GetEnvironmentVariableW(ASCIIToWide(env_vars::kShowRestart
).c_str(),
414 DWORD len
= ::GetEnvironmentVariableW(
415 ASCIIToWide(env_vars::kRestartInfo
).c_str(), NULL
, 0);
419 wchar_t* restart_data
= new wchar_t[len
+ 1];
420 ::GetEnvironmentVariableW(ASCIIToWide(env_vars::kRestartInfo
).c_str(),
422 restart_data
[len
] = 0;
423 // The CHROME_RESTART var contains the dialog strings separated by '|'.
424 // See PrepareRestartOnCrashEnviroment() function for details.
425 std::vector
<std::wstring
> dlg_strings
;
426 base::SplitString(restart_data
, L
'|', &dlg_strings
);
427 delete[] restart_data
;
428 if (dlg_strings
.size() < 3)
431 // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX
432 // flags so that an RTL message box is displayed.
433 UINT flags
= MB_OKCANCEL
| MB_ICONWARNING
;
434 if (dlg_strings
[2] == ASCIIToWide(env_vars::kRtlLocale
))
435 flags
|= MB_RIGHT
| MB_RTLREADING
;
437 return WrapMessageBoxWithSEH(dlg_strings
[1].c_str(), dlg_strings
[0].c_str(),
441 // Crashes the process after generating a dump for the provided exception. Note
442 // that the crash reporter should be initialized before calling this function
443 // for it to do anything.
444 extern "C" int __declspec(dllexport
) CrashForException(
445 EXCEPTION_POINTERS
* info
) {
447 g_breakpad
->WriteMinidumpForException(info
);
448 ::ExitProcess(ResultCodes::KILLED
);
450 return EXCEPTION_CONTINUE_SEARCH
;
453 // Determine whether configuration management allows loading the crash reporter.
454 // Since the configuration management infrastructure is not initialized at this
455 // point, we read the corresponding registry key directly. The return status
456 // indicates whether policy data was successfully read. If it is true, |result|
457 // contains the value set by policy.
458 static bool MetricsReportingControlledByPolicy(bool* result
) {
459 std::wstring key_name
= UTF8ToWide(policy::key::kMetricsReportingEnabled
);
461 // TODO(joshia): why hkcu_policy_key opens HKEY_LOCAL_MACHINE?
462 base::win::RegKey
hkcu_policy_key(HKEY_LOCAL_MACHINE
,
463 policy::kRegistrySubKey
, KEY_READ
);
464 if (hkcu_policy_key
.ReadValueDW(key_name
.c_str(), &value
) == ERROR_SUCCESS
) {
465 *result
= value
!= 0;
469 base::win::RegKey
hklm_policy_key(HKEY_CURRENT_USER
,
470 policy::kRegistrySubKey
, KEY_READ
);
471 if (hklm_policy_key
.ReadValueDW(key_name
.c_str(), &value
) == ERROR_SUCCESS
) {
472 *result
= value
!= 0;
479 static DWORD __stdcall
InitCrashReporterThread(void* param
) {
480 scoped_ptr
<CrashReporterInfo
> info(
481 reinterpret_cast<CrashReporterInfo
*>(param
));
483 // GetCustomInfo can take a few milliseconds to get the file information, so
484 // we do it here so it can run in a separate thread.
485 info
->custom_info
= GetCustomInfo(info
->dll_path
, info
->process_type
);
487 google_breakpad::ExceptionHandler::MinidumpCallback callback
= NULL
;
488 LPTOP_LEVEL_EXCEPTION_FILTER default_filter
= NULL
;
489 // We install the post-dump callback only for the browser and service
490 // processes. It spawns a new browser/service process.
491 if (info
->process_type
== L
"browser") {
492 callback
= &DumpDoneCallback
;
493 default_filter
= &ChromeExceptionFilter
;
494 } else if (info
->process_type
== L
"service") {
495 callback
= &DumpDoneCallback
;
496 default_filter
= &ServiceExceptionFilter
;
499 // Check whether configuration management controls crash reporting.
500 bool crash_reporting_enabled
= true;
501 bool controlled_by_policy
=
502 MetricsReportingControlledByPolicy(&crash_reporting_enabled
);
504 const CommandLine
& command
= *CommandLine::ForCurrentProcess();
505 bool use_crash_service
= !controlled_by_policy
&&
506 ((command
.HasSwitch(switches::kNoErrorDialogs
) ||
507 GetEnvironmentVariable(
508 ASCIIToWide(env_vars::kHeadless
).c_str(), NULL
, 0)));
509 bool is_per_user_install
=
510 InstallUtil::IsPerUserInstall(info
->dll_path
.c_str());
512 std::wstring pipe_name
;
513 if (use_crash_service
) {
514 // Crash reporting is done by crash_service.exe.
515 pipe_name
= kChromePipeName
;
517 // We want to use the Google Update crash reporting. We need to check if the
518 // user allows it first (in case the administrator didn't already decide
520 if (!controlled_by_policy
)
521 crash_reporting_enabled
= GoogleUpdateSettings::GetCollectStatsConsent();
523 if (!crash_reporting_enabled
) {
524 // Configuration managed or the user did not allow Google Update to send
525 // crashes, we need to use our default crash handler instead, but only
526 // for the browser/service processes.
528 InitDefaultCrashCallback(default_filter
);
532 // Build the pipe name. It can be either:
533 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
534 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
535 std::wstring user_sid
;
536 if (is_per_user_install
) {
537 if (!base::win::GetUserSidString(&user_sid
)) {
539 InitDefaultCrashCallback(default_filter
);
543 user_sid
= kSystemPrincipalSid
;
546 pipe_name
= kGoogleUpdatePipeName
;
547 pipe_name
+= user_sid
;
550 // Get the alternate dump directory. We use the temp path.
551 wchar_t temp_dir
[MAX_PATH
] = {0};
552 ::GetTempPathW(MAX_PATH
, temp_dir
);
554 MINIDUMP_TYPE dump_type
= kSmallDumpType
;
555 // Capture full memory if explicitly instructed to.
556 if (command
.HasSwitch(switches::kFullMemoryCrashReport
)) {
557 dump_type
= kFullDumpType
;
559 // Capture more detail in crash dumps for beta and dev channel builds.
560 string16 channel_string
;
561 GoogleUpdateSettings::GetChromeChannel(!is_per_user_install
,
563 if (channel_string
== L
"dev" || channel_string
== L
"beta" ||
564 channel_string
== GoogleChromeSxSDistribution::ChannelName())
565 dump_type
= kLargerDumpType
;
568 g_breakpad
= new google_breakpad::ExceptionHandler(temp_dir
, &FilterCallback
,
570 google_breakpad::ExceptionHandler::HANDLER_ALL
,
571 dump_type
, pipe_name
.c_str(), info
->custom_info
);
573 if (!g_breakpad
->IsOutOfProcess()) {
574 // The out-of-process handler is unavailable.
575 scoped_ptr
<base::Environment
> env(base::Environment::Create());
576 env
->SetVar(env_vars::kNoOOBreakpad
, WideToUTF8(info
->process_type
));
578 // Tells breakpad to handle breakpoint and single step exceptions.
579 // This might break JIT debuggers, but at least it will always
580 // generate a crashdump for these exceptions.
581 g_breakpad
->set_handle_debug_exceptions(true);
587 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter
) {
588 previous_filter
= SetUnhandledExceptionFilter(filter
);
591 void InitCrashReporterWithDllPath(const std::wstring
& dll_path
) {
592 const CommandLine
& command
= *CommandLine::ForCurrentProcess();
593 if (!command
.HasSwitch(switches::kDisableBreakpad
)) {
594 // Disable the message box for assertions.
595 _CrtSetReportMode(_CRT_ASSERT
, 0);
597 // Query the custom_info now because if we do it in the thread it's going to
598 // fail in the sandbox. The thread will delete this object.
599 CrashReporterInfo
* info(new CrashReporterInfo
);
600 info
->process_type
= command
.GetSwitchValueNative(switches::kProcessType
);
601 if (info
->process_type
.empty())
602 info
->process_type
= L
"browser";
604 info
->dll_path
= dll_path
;
606 // If this is not the browser, we can't be sure that we will be able to
607 // initialize the crash_handler in another thread, so we run it right away.
608 // This is important to keep the thread for the browser process because
609 // it may take some times to initialize the crash_service process. We use
610 // the Windows worker pool to make better reuse of the thread.
611 if (info
->process_type
!= L
"browser") {
612 InitCrashReporterThread(info
);
614 if (QueueUserWorkItem(
615 &InitCrashReporterThread
,
617 WT_EXECUTELONGFUNCTION
) == 0) {
618 // We failed to queue to the worker pool, initialize in this thread.
619 InitCrashReporterThread(info
);