OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/app/breakpad_win.h" | 5 #include "chrome/app/breakpad_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <shellapi.h> | 8 #include <shellapi.h> |
9 #include <tchar.h> | 9 #include <tchar.h> |
10 | 10 |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); | 319 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); |
320 } | 320 } |
321 | 321 |
322 static google_breakpad::CustomClientInfo custom_client_info; | 322 static google_breakpad::CustomClientInfo custom_client_info; |
323 custom_client_info.entries = &g_custom_entries->front(); | 323 custom_client_info.entries = &g_custom_entries->front(); |
324 custom_client_info.count = g_custom_entries->size(); | 324 custom_client_info.count = g_custom_entries->size(); |
325 | 325 |
326 return &custom_client_info; | 326 return &custom_client_info; |
327 } | 327 } |
328 | 328 |
329 // Contains the information needed by the worker thread. | 329 // Contains the information needed by InitCrashReporterMain(). |
330 struct CrashReporterInfo { | 330 struct CrashReporterInfo { |
331 google_breakpad::CustomClientInfo* custom_info; | 331 google_breakpad::CustomClientInfo* custom_info; |
332 std::wstring exe_path; | 332 std::wstring exe_path; |
333 std::wstring process_type; | 333 std::wstring process_type; |
334 }; | 334 }; |
335 | 335 |
336 // This callback is used when we want to get a dump without crashing the | 336 // This callback is used when we want to get a dump without crashing the |
337 // process. | 337 // process. |
338 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, | 338 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, |
339 EXCEPTION_POINTERS* ex_info, | 339 EXCEPTION_POINTERS* ex_info, |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 base::win::RegKey hkcu_policy_key(HKEY_CURRENT_USER, | 598 base::win::RegKey hkcu_policy_key(HKEY_CURRENT_USER, |
599 policy::kRegistryMandatorySubKey, KEY_READ); | 599 policy::kRegistryMandatorySubKey, KEY_READ); |
600 if (hkcu_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) { | 600 if (hkcu_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) { |
601 *result = value != 0; | 601 *result = value != 0; |
602 return true; | 602 return true; |
603 } | 603 } |
604 | 604 |
605 return false; | 605 return false; |
606 } | 606 } |
607 | 607 |
608 static DWORD __stdcall InitCrashReporterThread(void* param) { | 608 // TODO(mseaborn): This function could be merged with InitCrashReporter(). |
609 scoped_ptr<CrashReporterInfo> info( | 609 static void InitCrashReporterMain(CrashReporterInfo* param) { |
610 reinterpret_cast<CrashReporterInfo*>(param)); | 610 scoped_ptr<CrashReporterInfo> info(param); |
611 | 611 |
612 bool is_per_user_install = | 612 bool is_per_user_install = |
613 InstallUtil::IsPerUserInstall(info->exe_path.c_str()); | 613 InstallUtil::IsPerUserInstall(info->exe_path.c_str()); |
614 | 614 |
615 std::wstring channel_string; | 615 std::wstring channel_string; |
616 GoogleUpdateSettings::GetChromeChannelAndModifiers(!is_per_user_install, | 616 GoogleUpdateSettings::GetChromeChannelAndModifiers(!is_per_user_install, |
617 &channel_string); | 617 &channel_string); |
618 | 618 |
619 // GetCustomInfo can take a few milliseconds to get the file information, so | |
620 // we do it here so it can run in a separate thread. | |
621 info->custom_info = GetCustomInfo(info->exe_path, info->process_type, | 619 info->custom_info = GetCustomInfo(info->exe_path, info->process_type, |
622 channel_string); | 620 channel_string); |
623 | 621 |
624 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; | 622 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; |
625 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; | 623 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; |
626 // We install the post-dump callback only for the browser and service | 624 // We install the post-dump callback only for the browser and service |
627 // processes. It spawns a new browser/service process. | 625 // processes. It spawns a new browser/service process. |
628 if (info->process_type == L"browser") { | 626 if (info->process_type == L"browser") { |
629 callback = &DumpDoneCallback; | 627 callback = &DumpDoneCallback; |
630 default_filter = &ChromeExceptionFilter; | 628 default_filter = &ChromeExceptionFilter; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 // via policy). | 660 // via policy). |
663 if (!controlled_by_policy) | 661 if (!controlled_by_policy) |
664 crash_reporting_enabled = GoogleUpdateSettings::GetCollectStatsConsent(); | 662 crash_reporting_enabled = GoogleUpdateSettings::GetCollectStatsConsent(); |
665 | 663 |
666 if (!crash_reporting_enabled) { | 664 if (!crash_reporting_enabled) { |
667 // Configuration managed or the user did not allow Google Update to send | 665 // Configuration managed or the user did not allow Google Update to send |
668 // crashes, we need to use our default crash handler instead, but only | 666 // crashes, we need to use our default crash handler instead, but only |
669 // for the browser/service processes. | 667 // for the browser/service processes. |
670 if (default_filter) | 668 if (default_filter) |
671 InitDefaultCrashCallback(default_filter); | 669 InitDefaultCrashCallback(default_filter); |
672 return 0; | 670 return; |
673 } | 671 } |
674 | 672 |
675 // Build the pipe name. It can be either: | 673 // Build the pipe name. It can be either: |
676 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" | 674 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" |
677 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" | 675 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" |
678 std::wstring user_sid; | 676 std::wstring user_sid; |
679 if (is_per_user_install) { | 677 if (is_per_user_install) { |
680 if (!base::win::GetUserSidString(&user_sid)) { | 678 if (!base::win::GetUserSidString(&user_sid)) { |
681 if (default_filter) | 679 if (default_filter) |
682 InitDefaultCrashCallback(default_filter); | 680 InitDefaultCrashCallback(default_filter); |
683 return -1; | 681 return; |
684 } | 682 } |
685 } else { | 683 } else { |
686 user_sid = kSystemPrincipalSid; | 684 user_sid = kSystemPrincipalSid; |
687 } | 685 } |
688 | 686 |
689 pipe_name = kGoogleUpdatePipeName; | 687 pipe_name = kGoogleUpdatePipeName; |
690 pipe_name += user_sid; | 688 pipe_name += user_sid; |
691 } | 689 } |
692 #ifdef _WIN64 | 690 #ifdef _WIN64 |
693 // The protocol for connecting to the out-of-process Breakpad crash | 691 // The protocol for connecting to the out-of-process Breakpad crash |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 // handlers. | 729 // handlers. |
732 google_breakpad::ExceptionHandler::HANDLER_NONE, | 730 google_breakpad::ExceptionHandler::HANDLER_NONE, |
733 dump_type, pipe_name.c_str(), info->custom_info); | 731 dump_type, pipe_name.c_str(), info->custom_info); |
734 | 732 |
735 if (g_breakpad->IsOutOfProcess()) { | 733 if (g_breakpad->IsOutOfProcess()) { |
736 // Tells breakpad to handle breakpoint and single step exceptions. | 734 // Tells breakpad to handle breakpoint and single step exceptions. |
737 // This might break JIT debuggers, but at least it will always | 735 // This might break JIT debuggers, but at least it will always |
738 // generate a crashdump for these exceptions. | 736 // generate a crashdump for these exceptions. |
739 g_breakpad->set_handle_debug_exceptions(true); | 737 g_breakpad->set_handle_debug_exceptions(true); |
740 } | 738 } |
741 | |
742 return 0; | |
743 } | 739 } |
744 | 740 |
745 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { | 741 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { |
746 previous_filter = SetUnhandledExceptionFilter(filter); | 742 previous_filter = SetUnhandledExceptionFilter(filter); |
747 } | 743 } |
748 | 744 |
749 void InitCrashReporter() { | 745 void InitCrashReporter() { |
750 const CommandLine& command = *CommandLine::ForCurrentProcess(); | 746 const CommandLine& command = *CommandLine::ForCurrentProcess(); |
751 if (!command.HasSwitch(switches::kDisableBreakpad)) { | 747 if (!command.HasSwitch(switches::kDisableBreakpad)) { |
752 // Disable the message box for assertions. | 748 // Disable the message box for assertions. |
753 _CrtSetReportMode(_CRT_ASSERT, 0); | 749 _CrtSetReportMode(_CRT_ASSERT, 0); |
754 | 750 |
755 // Query the custom_info now because if we do it in the thread it's going to | |
756 // fail in the sandbox. The thread will delete this object. | |
757 CrashReporterInfo* info(new CrashReporterInfo); | 751 CrashReporterInfo* info(new CrashReporterInfo); |
758 info->process_type = command.GetSwitchValueNative(switches::kProcessType); | 752 info->process_type = command.GetSwitchValueNative(switches::kProcessType); |
759 if (info->process_type.empty()) | 753 if (info->process_type.empty()) |
760 info->process_type = L"browser"; | 754 info->process_type = L"browser"; |
761 | 755 |
762 wchar_t exe_path[MAX_PATH]; | 756 wchar_t exe_path[MAX_PATH]; |
763 exe_path[0] = 0; | 757 exe_path[0] = 0; |
764 GetModuleFileNameW(NULL, exe_path, MAX_PATH); | 758 GetModuleFileNameW(NULL, exe_path, MAX_PATH); |
765 info->exe_path = exe_path; | 759 info->exe_path = exe_path; |
766 | 760 |
767 // If this is not the browser, we can't be sure that we will be able to | 761 InitCrashReporterMain(info); |
768 // initialize the crash_handler in another thread, so we run it right away. | |
769 // This is important to keep the thread for the browser process because | |
770 // it may take some times to initialize the crash_service process. We use | |
771 // the Windows worker pool to make better reuse of the thread. | |
772 if (info->process_type != L"browser") { | |
773 InitCrashReporterThread(info); | |
774 } else { | |
775 if (QueueUserWorkItem( | |
776 &InitCrashReporterThread, | |
777 info, | |
778 WT_EXECUTELONGFUNCTION) == 0) { | |
779 // We failed to queue to the worker pool, initialize in this thread. | |
780 InitCrashReporterThread(info); | |
781 } | |
782 } | |
783 } | 762 } |
784 } | 763 } |
OLD | NEW |