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 InitCrashReporterMain(). | 329 // Contains the information needed by the worker thread. |
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 // TODO(mseaborn): This function could be merged with InitCrashReporter(). | 608 static DWORD __stdcall InitCrashReporterThread(void* param) { |
609 static void InitCrashReporterMain(CrashReporterInfo* param) { | 609 scoped_ptr<CrashReporterInfo> info( |
610 scoped_ptr<CrashReporterInfo> info(param); | 610 reinterpret_cast<CrashReporterInfo*>(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. |
619 info->custom_info = GetCustomInfo(info->exe_path, info->process_type, | 621 info->custom_info = GetCustomInfo(info->exe_path, info->process_type, |
620 channel_string); | 622 channel_string); |
621 | 623 |
622 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; | 624 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; |
623 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; | 625 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; |
624 // We install the post-dump callback only for the browser and service | 626 // We install the post-dump callback only for the browser and service |
625 // processes. It spawns a new browser/service process. | 627 // processes. It spawns a new browser/service process. |
626 if (info->process_type == L"browser") { | 628 if (info->process_type == L"browser") { |
627 callback = &DumpDoneCallback; | 629 callback = &DumpDoneCallback; |
628 default_filter = &ChromeExceptionFilter; | 630 default_filter = &ChromeExceptionFilter; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 // via policy). | 662 // via policy). |
661 if (!controlled_by_policy) | 663 if (!controlled_by_policy) |
662 crash_reporting_enabled = GoogleUpdateSettings::GetCollectStatsConsent(); | 664 crash_reporting_enabled = GoogleUpdateSettings::GetCollectStatsConsent(); |
663 | 665 |
664 if (!crash_reporting_enabled) { | 666 if (!crash_reporting_enabled) { |
665 // Configuration managed or the user did not allow Google Update to send | 667 // Configuration managed or the user did not allow Google Update to send |
666 // crashes, we need to use our default crash handler instead, but only | 668 // crashes, we need to use our default crash handler instead, but only |
667 // for the browser/service processes. | 669 // for the browser/service processes. |
668 if (default_filter) | 670 if (default_filter) |
669 InitDefaultCrashCallback(default_filter); | 671 InitDefaultCrashCallback(default_filter); |
670 return; | 672 return 0; |
671 } | 673 } |
672 | 674 |
673 // Build the pipe name. It can be either: | 675 // Build the pipe name. It can be either: |
674 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" | 676 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" |
675 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" | 677 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" |
676 std::wstring user_sid; | 678 std::wstring user_sid; |
677 if (is_per_user_install) { | 679 if (is_per_user_install) { |
678 if (!base::win::GetUserSidString(&user_sid)) { | 680 if (!base::win::GetUserSidString(&user_sid)) { |
679 if (default_filter) | 681 if (default_filter) |
680 InitDefaultCrashCallback(default_filter); | 682 InitDefaultCrashCallback(default_filter); |
681 return; | 683 return -1; |
682 } | 684 } |
683 } else { | 685 } else { |
684 user_sid = kSystemPrincipalSid; | 686 user_sid = kSystemPrincipalSid; |
685 } | 687 } |
686 | 688 |
687 pipe_name = kGoogleUpdatePipeName; | 689 pipe_name = kGoogleUpdatePipeName; |
688 pipe_name += user_sid; | 690 pipe_name += user_sid; |
689 } | 691 } |
690 #ifdef _WIN64 | 692 #ifdef _WIN64 |
691 // The protocol for connecting to the out-of-process Breakpad crash | 693 // The protocol for connecting to the out-of-process Breakpad crash |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 // handlers. | 731 // handlers. |
730 google_breakpad::ExceptionHandler::HANDLER_NONE, | 732 google_breakpad::ExceptionHandler::HANDLER_NONE, |
731 dump_type, pipe_name.c_str(), info->custom_info); | 733 dump_type, pipe_name.c_str(), info->custom_info); |
732 | 734 |
733 if (g_breakpad->IsOutOfProcess()) { | 735 if (g_breakpad->IsOutOfProcess()) { |
734 // Tells breakpad to handle breakpoint and single step exceptions. | 736 // Tells breakpad to handle breakpoint and single step exceptions. |
735 // This might break JIT debuggers, but at least it will always | 737 // This might break JIT debuggers, but at least it will always |
736 // generate a crashdump for these exceptions. | 738 // generate a crashdump for these exceptions. |
737 g_breakpad->set_handle_debug_exceptions(true); | 739 g_breakpad->set_handle_debug_exceptions(true); |
738 } | 740 } |
| 741 |
| 742 return 0; |
739 } | 743 } |
740 | 744 |
741 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { | 745 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { |
742 previous_filter = SetUnhandledExceptionFilter(filter); | 746 previous_filter = SetUnhandledExceptionFilter(filter); |
743 } | 747 } |
744 | 748 |
745 void InitCrashReporter() { | 749 void InitCrashReporter() { |
746 const CommandLine& command = *CommandLine::ForCurrentProcess(); | 750 const CommandLine& command = *CommandLine::ForCurrentProcess(); |
747 if (!command.HasSwitch(switches::kDisableBreakpad)) { | 751 if (!command.HasSwitch(switches::kDisableBreakpad)) { |
748 // Disable the message box for assertions. | 752 // Disable the message box for assertions. |
749 _CrtSetReportMode(_CRT_ASSERT, 0); | 753 _CrtSetReportMode(_CRT_ASSERT, 0); |
750 | 754 |
| 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. |
751 CrashReporterInfo* info(new CrashReporterInfo); | 757 CrashReporterInfo* info(new CrashReporterInfo); |
752 info->process_type = command.GetSwitchValueNative(switches::kProcessType); | 758 info->process_type = command.GetSwitchValueNative(switches::kProcessType); |
753 if (info->process_type.empty()) | 759 if (info->process_type.empty()) |
754 info->process_type = L"browser"; | 760 info->process_type = L"browser"; |
755 | 761 |
756 wchar_t exe_path[MAX_PATH]; | 762 wchar_t exe_path[MAX_PATH]; |
757 exe_path[0] = 0; | 763 exe_path[0] = 0; |
758 GetModuleFileNameW(NULL, exe_path, MAX_PATH); | 764 GetModuleFileNameW(NULL, exe_path, MAX_PATH); |
759 info->exe_path = exe_path; | 765 info->exe_path = exe_path; |
760 | 766 |
761 InitCrashReporterMain(info); | 767 // If this is not the browser, we can't be sure that we will be able to |
| 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 } |
762 } | 783 } |
763 } | 784 } |
OLD | NEW |