| 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 <shellapi.h> | 7 #include <shellapi.h> |
| 8 #include <tchar.h> | 8 #include <tchar.h> |
| 9 #include <userenv.h> | 9 #include <userenv.h> |
| 10 #include <windows.h> | 10 #include <windows.h> |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "base/strings/utf_string_conversions.h" | 25 #include "base/strings/utf_string_conversions.h" |
| 26 #include "base/win/metro.h" | 26 #include "base/win/metro.h" |
| 27 #include "base/win/pe_image.h" | 27 #include "base/win/pe_image.h" |
| 28 #include "base/win/registry.h" | 28 #include "base/win/registry.h" |
| 29 #include "base/win/win_util.h" | 29 #include "base/win/win_util.h" |
| 30 #include "breakpad/src/client/windows/handler/exception_handler.h" | 30 #include "breakpad/src/client/windows/handler/exception_handler.h" |
| 31 #include "chrome/app/breakpad_field_trial_win.h" | 31 #include "chrome/app/breakpad_field_trial_win.h" |
| 32 #include "chrome/app/hard_error_handler_win.h" | 32 #include "chrome/app/hard_error_handler_win.h" |
| 33 #include "chrome/common/child_process_logging.h" | 33 #include "chrome/common/child_process_logging.h" |
| 34 #include "chrome/common/chrome_result_codes.h" | 34 #include "chrome/common/chrome_result_codes.h" |
| 35 #include "chrome/common/env_vars.h" | |
| 36 #include "chrome/installer/util/google_chrome_sxs_distribution.h" | 35 #include "chrome/installer/util/google_chrome_sxs_distribution.h" |
| 37 #include "chrome/installer/util/google_update_settings.h" | 36 #include "chrome/installer/util/google_update_settings.h" |
| 38 #include "chrome/installer/util/install_util.h" | 37 #include "chrome/installer/util/install_util.h" |
| 39 #include "components/breakpad/breakpad_client.h" | 38 #include "components/breakpad/breakpad_client.h" |
| 40 #include "content/public/common/content_switches.h" | 39 #include "content/public/common/content_switches.h" |
| 41 #include "policy/policy_constants.h" | 40 #include "policy/policy_constants.h" |
| 42 #include "sandbox/win/src/nt_internals.h" | 41 #include "sandbox/win/src/nt_internals.h" |
| 43 #include "sandbox/win/src/sidestep/preamble_patcher.h" | 42 #include "sandbox/win/src/sidestep/preamble_patcher.h" |
| 44 | 43 |
| 45 // userenv.dll is required for GetProfileType(). | 44 // userenv.dll is required for GetProfileType(). |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 } else { | 481 } else { |
| 483 g_custom_entries->push_back( | 482 g_custom_entries->push_back( |
| 484 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); | 483 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); |
| 485 } | 484 } |
| 486 | 485 |
| 487 // Check whether configuration management controls crash reporting. | 486 // Check whether configuration management controls crash reporting. |
| 488 bool crash_reporting_enabled = true; | 487 bool crash_reporting_enabled = true; |
| 489 bool controlled_by_policy = | 488 bool controlled_by_policy = |
| 490 MetricsReportingControlledByPolicy(&crash_reporting_enabled); | 489 MetricsReportingControlledByPolicy(&crash_reporting_enabled); |
| 491 const CommandLine& command = *CommandLine::ForCurrentProcess(); | 490 const CommandLine& command = *CommandLine::ForCurrentProcess(); |
| 492 bool use_crash_service = !controlled_by_policy && | 491 bool use_crash_service = |
| 493 ((command.HasSwitch(switches::kNoErrorDialogs) || | 492 !controlled_by_policy && |
| 494 GetEnvironmentVariable( | 493 (command.HasSwitch(switches::kNoErrorDialogs) || |
| 495 ASCIIToWide(env_vars::kHeadless).c_str(), NULL, 0))); | 494 breakpad::GetBreakpadClient()->IsRunningUnattended()); |
| 496 if (use_crash_service) | 495 if (use_crash_service) |
| 497 SetBreakpadDumpPath(); | 496 SetBreakpadDumpPath(); |
| 498 | 497 |
| 499 g_num_of_experiments_offset = g_custom_entries->size(); | 498 g_num_of_experiments_offset = g_custom_entries->size(); |
| 500 g_custom_entries->push_back( | 499 g_custom_entries->push_back( |
| 501 google_breakpad::CustomInfoEntry(L"num-experiments", L"N/A")); | 500 google_breakpad::CustomInfoEntry(L"num-experiments", L"N/A")); |
| 502 | 501 |
| 503 g_experiment_chunks_offset = g_custom_entries->size(); | 502 g_experiment_chunks_offset = g_custom_entries->size(); |
| 504 // We depend on this in UpdateExperiments... | 503 // We depend on this in UpdateExperiments... |
| 505 DCHECK_NE(0UL, g_experiment_chunks_offset); | 504 DCHECK_NE(0UL, g_experiment_chunks_offset); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*, | 547 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*, |
| 549 EXCEPTION_POINTERS* ex_info, | 548 EXCEPTION_POINTERS* ex_info, |
| 550 MDRawAssertionInfo*, bool) { | 549 MDRawAssertionInfo*, bool) { |
| 551 // Check if the exception is one of the kind which would not be solved | 550 // Check if the exception is one of the kind which would not be solved |
| 552 // by simply restarting chrome. In this case we show a message box with | 551 // by simply restarting chrome. In this case we show a message box with |
| 553 // and exit silently. Remember that chrome is in a crashed state so we | 552 // and exit silently. Remember that chrome is in a crashed state so we |
| 554 // can't show our own UI from this process. | 553 // can't show our own UI from this process. |
| 555 if (HardErrorHandler(ex_info)) | 554 if (HardErrorHandler(ex_info)) |
| 556 return true; | 555 return true; |
| 557 | 556 |
| 558 // We set CHROME_CRASHED env var. If the CHROME_RESTART is present. | 557 if (!breakpad::GetBreakpadClient()->AboutToRestart()) |
| 559 // This signals the child process to show the 'chrome has crashed' dialog. | |
| 560 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 561 if (!env->HasVar(env_vars::kRestartInfo)) { | |
| 562 return true; | 558 return true; |
| 563 } | 559 |
| 564 env->SetVar(env_vars::kShowRestart, "1"); | |
| 565 // Now we just start chrome browser with the same command line. | 560 // Now we just start chrome browser with the same command line. |
| 566 STARTUPINFOW si = {sizeof(si)}; | 561 STARTUPINFOW si = {sizeof(si)}; |
| 567 PROCESS_INFORMATION pi; | 562 PROCESS_INFORMATION pi; |
| 568 if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE, | 563 if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE, |
| 569 CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) { | 564 CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) { |
| 570 ::CloseHandle(pi.hProcess); | 565 ::CloseHandle(pi.hProcess); |
| 571 ::CloseHandle(pi.hThread); | 566 ::CloseHandle(pi.hThread); |
| 572 } | 567 } |
| 573 // After this return we will be terminated. The actual return value is | 568 // After this return we will be terminated. The actual return value is |
| 574 // not used at all. | 569 // not used at all. |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 chrome::RESULT_CODE_RESPAWN_FAILED); | 789 chrome::RESULT_CODE_RESPAWN_FAILED); |
| 795 } | 790 } |
| 796 | 791 |
| 797 return true; | 792 return true; |
| 798 } | 793 } |
| 799 | 794 |
| 800 // This function is executed by the child process that DumpDoneCallback() | 795 // This function is executed by the child process that DumpDoneCallback() |
| 801 // spawned and basically just shows the 'chrome has crashed' dialog if | 796 // spawned and basically just shows the 'chrome has crashed' dialog if |
| 802 // the CHROME_CRASHED environment variable is present. | 797 // the CHROME_CRASHED environment variable is present. |
| 803 bool ShowRestartDialogIfCrashed(bool* exit_now) { | 798 bool ShowRestartDialogIfCrashed(bool* exit_now) { |
| 804 if (!::GetEnvironmentVariableW(ASCIIToWide(env_vars::kShowRestart).c_str(), | |
| 805 NULL, 0)) { | |
| 806 return false; | |
| 807 } | |
| 808 | |
| 809 // If we are being launched in metro mode don't try to show the dialog. | 799 // If we are being launched in metro mode don't try to show the dialog. |
| 810 if (base::win::IsMetroProcess()) | 800 if (base::win::IsMetroProcess()) |
| 811 return false; | 801 return false; |
| 812 | 802 |
| 813 // Only show this for the browser process. See crbug.com/132119. | 803 // Only show this for the browser process. See crbug.com/132119. |
| 814 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 804 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 815 std::string process_type = | 805 std::string process_type = |
| 816 command_line.GetSwitchValueASCII(switches::kProcessType); | 806 command_line.GetSwitchValueASCII(switches::kProcessType); |
| 817 if (!process_type.empty()) { | 807 if (!process_type.empty()) |
| 808 return false; |
| 809 |
| 810 base::string16 message; |
| 811 base::string16 title; |
| 812 bool is_rtl_locale; |
| 813 if (!breakpad::GetBreakpadClient()->ShouldShowRestartDialog( |
| 814 &title, &message, &is_rtl_locale)) { |
| 818 return false; | 815 return false; |
| 819 } | 816 } |
| 820 | 817 |
| 821 DWORD len = ::GetEnvironmentVariableW( | |
| 822 ASCIIToWide(env_vars::kRestartInfo).c_str(), NULL, 0); | |
| 823 if (!len) | |
| 824 return true; | |
| 825 | |
| 826 wchar_t* restart_data = new wchar_t[len + 1]; | |
| 827 ::GetEnvironmentVariableW(ASCIIToWide(env_vars::kRestartInfo).c_str(), | |
| 828 restart_data, len); | |
| 829 restart_data[len] = 0; | |
| 830 // The CHROME_RESTART var contains the dialog strings separated by '|'. | |
| 831 // See ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment() | |
| 832 // for details. | |
| 833 std::vector<std::wstring> dlg_strings; | |
| 834 base::SplitString(restart_data, L'|', &dlg_strings); | |
| 835 delete[] restart_data; | |
| 836 if (dlg_strings.size() < 3) | |
| 837 return true; | |
| 838 | |
| 839 // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX | 818 // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX |
| 840 // flags so that an RTL message box is displayed. | 819 // flags so that an RTL message box is displayed. |
| 841 UINT flags = MB_OKCANCEL | MB_ICONWARNING; | 820 UINT flags = MB_OKCANCEL | MB_ICONWARNING; |
| 842 if (dlg_strings[2] == ASCIIToWide(env_vars::kRtlLocale)) | 821 if (is_rtl_locale) |
| 843 flags |= MB_RIGHT | MB_RTLREADING; | 822 flags |= MB_RIGHT | MB_RTLREADING; |
| 844 | 823 |
| 845 return WrapMessageBoxWithSEH(dlg_strings[1].c_str(), dlg_strings[0].c_str(), | 824 return WrapMessageBoxWithSEH(base::UTF16ToWide(message).c_str(), |
| 846 flags, exit_now); | 825 base::UTF16ToWide(title).c_str(), |
| 826 flags, |
| 827 exit_now); |
| 847 } | 828 } |
| 848 | 829 |
| 849 // Crashes the process after generating a dump for the provided exception. Note | 830 // Crashes the process after generating a dump for the provided exception. Note |
| 850 // that the crash reporter should be initialized before calling this function | 831 // that the crash reporter should be initialized before calling this function |
| 851 // for it to do anything. | 832 // for it to do anything. |
| 852 extern "C" int __declspec(dllexport) CrashForException( | 833 extern "C" int __declspec(dllexport) CrashForException( |
| 853 EXCEPTION_POINTERS* info) { | 834 EXCEPTION_POINTERS* info) { |
| 854 if (g_breakpad) { | 835 if (g_breakpad) { |
| 855 g_breakpad->WriteMinidumpForException(info); | 836 g_breakpad->WriteMinidumpForException(info); |
| 856 // Patched stub exists based on conditions (See InitCrashReporter). | 837 // Patched stub exists based on conditions (See InitCrashReporter). |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 // The Breakpad pipe name is already configured: nothing to do. | 933 // The Breakpad pipe name is already configured: nothing to do. |
| 953 return; | 934 return; |
| 954 } | 935 } |
| 955 | 936 |
| 956 // Check whether configuration management controls crash reporting. | 937 // Check whether configuration management controls crash reporting. |
| 957 bool crash_reporting_enabled = true; | 938 bool crash_reporting_enabled = true; |
| 958 bool controlled_by_policy = | 939 bool controlled_by_policy = |
| 959 MetricsReportingControlledByPolicy(&crash_reporting_enabled); | 940 MetricsReportingControlledByPolicy(&crash_reporting_enabled); |
| 960 | 941 |
| 961 const CommandLine& command = *CommandLine::ForCurrentProcess(); | 942 const CommandLine& command = *CommandLine::ForCurrentProcess(); |
| 962 bool use_crash_service = !controlled_by_policy && | 943 bool use_crash_service = |
| 963 ((command.HasSwitch(switches::kNoErrorDialogs) || | 944 !controlled_by_policy && |
| 964 GetEnvironmentVariable( | 945 (command.HasSwitch(switches::kNoErrorDialogs) || |
| 965 ASCIIToWide(env_vars::kHeadless).c_str(), NULL, 0))); | 946 breakpad::GetBreakpadClient()->IsRunningUnattended()); |
| 966 | 947 |
| 967 std::wstring pipe_name; | 948 std::wstring pipe_name; |
| 968 if (use_crash_service) { | 949 if (use_crash_service) { |
| 969 // Crash reporting is done by crash_service.exe. | 950 // Crash reporting is done by crash_service.exe. |
| 970 pipe_name = kChromePipeName; | 951 pipe_name = kChromePipeName; |
| 971 } else { | 952 } else { |
| 972 // We want to use the Google Update crash reporting. We need to check if the | 953 // We want to use the Google Update crash reporting. We need to check if the |
| 973 // user allows it first (in case the administrator didn't already decide | 954 // user allows it first (in case the administrator didn't already decide |
| 974 // via policy). | 955 // via policy). |
| 975 if (!controlled_by_policy) | 956 if (!controlled_by_policy) |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1103 dump_type, pipe_name.c_str(), custom_info); | 1084 dump_type, pipe_name.c_str(), custom_info); |
| 1104 | 1085 |
| 1105 if (g_breakpad->IsOutOfProcess()) { | 1086 if (g_breakpad->IsOutOfProcess()) { |
| 1106 // Tells breakpad to handle breakpoint and single step exceptions. | 1087 // Tells breakpad to handle breakpoint and single step exceptions. |
| 1107 // This might break JIT debuggers, but at least it will always | 1088 // This might break JIT debuggers, but at least it will always |
| 1108 // generate a crashdump for these exceptions. | 1089 // generate a crashdump for these exceptions. |
| 1109 g_breakpad->set_handle_debug_exceptions(true); | 1090 g_breakpad->set_handle_debug_exceptions(true); |
| 1110 | 1091 |
| 1111 #ifndef _WIN64 | 1092 #ifndef _WIN64 |
| 1112 std::string headless; | 1093 std::string headless; |
| 1113 if (process_type != L"browser" && !GetEnvironmentVariable( | 1094 if (process_type != L"browser" && |
| 1114 ASCIIToWide(env_vars::kHeadless).c_str(), NULL, 0)) { | 1095 !breakpad::GetBreakpadClient()->IsRunningUnattended()) { |
| 1115 // Initialize the hook TerminateProcess to catch unexpected exits. | 1096 // Initialize the hook TerminateProcess to catch unexpected exits. |
| 1116 InitTerminateProcessHooks(); | 1097 InitTerminateProcessHooks(); |
| 1117 } | 1098 } |
| 1118 #endif | 1099 #endif |
| 1119 } | 1100 } |
| 1120 } | 1101 } |
| 1121 | 1102 |
| 1122 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { | 1103 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { |
| 1123 previous_filter = SetUnhandledExceptionFilter(filter); | 1104 previous_filter = SetUnhandledExceptionFilter(filter); |
| 1124 } | 1105 } |
| 1125 | 1106 |
| 1126 void StringVectorToCStringVector(const std::vector<std::wstring>& wstrings, | 1107 void StringVectorToCStringVector(const std::vector<std::wstring>& wstrings, |
| 1127 std::vector<const wchar_t*>* cstrings) { | 1108 std::vector<const wchar_t*>* cstrings) { |
| 1128 cstrings->clear(); | 1109 cstrings->clear(); |
| 1129 cstrings->reserve(wstrings.size()); | 1110 cstrings->reserve(wstrings.size()); |
| 1130 for (size_t i = 0; i < wstrings.size(); ++i) | 1111 for (size_t i = 0; i < wstrings.size(); ++i) |
| 1131 cstrings->push_back(wstrings[i].c_str()); | 1112 cstrings->push_back(wstrings[i].c_str()); |
| 1132 } | 1113 } |
| OLD | NEW |