diff options
author | scottmg <scottmg@chromium.org> | 2015-11-30 15:13:46 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-30 23:14:45 +0000 |
commit | cfa5b01bb1d06bf96967bd37e21a44752801948c (patch) | |
tree | 482d6cba1afc8cc6c3a8ea15749c43ec97e6f9f1 | |
parent | 3cd4753b98c9bb96618ec71ebac2c14a02182a97 (diff) | |
download | chromium_src-cfa5b01bb1d06bf96967bd37e21a44752801948c.zip chromium_src-cfa5b01bb1d06bf96967bd37e21a44752801948c.tar.gz chromium_src-cfa5b01bb1d06bf96967bd37e21a44752801948c.tar.bz2 |
Reland: Crashpad Windows: Use the Crashpad client instead of Breakpad on Windows
Changes since https://codereview.chromium.org/1416133003 are ps1 -> ps2.
- Includes build fix to for debug component GN build.
- Includes Crashpad roll to pull in clang compile fixes and a limit on
the number of locks saved to the crash dump.
- Increase timeout on tab crash telemetry test for debug builds.
Original CL:
Crashpad Windows: Use the Crashpad client instead of Breakpad on Windows
Crashpad is always compiled into chrome and its handler is always
enabled. It only uploads in Official builds.
On Windows, the crash handler is chrome.exe run with a
--crashpad-handler argument. This is due to concern about
incompatibilities of shipping an additional new different binary for AV,
firewalls, etc.
Sample renderer crash/1aed2bc785e28995
Sample browser: crash/66c822815474a5d8
See also http://crbug.com/427611 .
R=mark@chromium.org
TBR=cpu@chromium.org
BUG=447073, 546288, 456193
Review URL: https://codereview.chromium.org/1479283002
Cr-Commit-Position: refs/heads/master@{#362258}
47 files changed, 985 insertions, 564 deletions
@@ -127,7 +127,7 @@ deps = { Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', 'src/third_party/crashpad/crashpad': - Var('chromium_git') + '/crashpad/crashpad.git' + '@' + '97b0f86d0ccb095391ca64b3948f0d6c02975ac1', + Var('chromium_git') + '/crashpad/crashpad.git' + '@' + '1f3ced1846f3956e678c562c90e0d6c970543617', 'src/third_party/icu': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '42c58d4e49f2250039f0e98d43e0b76e8f5ca024', diff --git a/build/secondary/third_party/crashpad/crashpad/client/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/client/BUILD.gn index 5cfadfa..4ebb22d 100644 --- a/build/secondary/third_party/crashpad/crashpad/client/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/client/BUILD.gn @@ -8,8 +8,6 @@ config("client_config") { source_set("client") { sources = [ - "capture_context_mac.S", - "capture_context_mac.h", "crash_report_database.cc", "crash_report_database.h", "crash_report_database_mac.mm", @@ -31,6 +29,13 @@ source_set("client") { "simulate_crash_win.h", ] + if (is_mac) { + sources += [ + "capture_context_mac.S", + "capture_context_mac.h", + ] + } + public_configs = [ ":client_config" ] deps = [ diff --git a/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn new file mode 100644 index 0000000..9ad3464 --- /dev/null +++ b/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("handler_lib") { + sources = [ + "crash_report_upload_thread.cc", + "crash_report_upload_thread.h", + "handler_main.cc", + "handler_main.h", + "mac/crash_report_exception_handler.cc", + "mac/crash_report_exception_handler.h", + "mac/exception_handler_server.cc", + "mac/exception_handler_server.h", + "win/crash_report_exception_handler.cc", + "win/crash_report_exception_handler.h", + ] + + include_dirs = [ ".." ] + + deps = [ + "../compat", + "../minidump", + "../snapshot", + "../tools:tool_support", + "//base", + ] + + if (is_win) { + cflags = [ "/wd4201" ] + } +} + +executable("crashpad_handler") { + sources = [ + "main.cc", + ] + + include_dirs = [ ".." ] + + deps = [ + ":handler_lib", + "../compat", + "//base", + ] +} diff --git a/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn new file mode 100644 index 0000000..f23aa4d --- /dev/null +++ b/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("minidump") { + deps = [ + "../compat", + "../snapshot", + "../util", + "//base", + ] + + include_dirs = [ ".." ] + + if (is_win) { + cflags = [ + "/wd4201", + "/wd4324", + ] + } + + sources = [ + "minidump_context.h", + "minidump_context_writer.cc", + "minidump_context_writer.h", + "minidump_crashpad_info_writer.cc", + "minidump_crashpad_info_writer.h", + "minidump_exception_writer.cc", + "minidump_exception_writer.h", + "minidump_extensions.cc", + "minidump_extensions.h", + "minidump_file_writer.cc", + "minidump_file_writer.h", + "minidump_handle_writer.cc", + "minidump_handle_writer.h", + "minidump_memory_info_writer.cc", + "minidump_memory_info_writer.h", + "minidump_memory_writer.cc", + "minidump_memory_writer.h", + "minidump_misc_info_writer.cc", + "minidump_misc_info_writer.h", + "minidump_module_crashpad_info_writer.cc", + "minidump_module_crashpad_info_writer.h", + "minidump_module_writer.cc", + "minidump_module_writer.h", + "minidump_rva_list_writer.cc", + "minidump_rva_list_writer.h", + "minidump_simple_string_dictionary_writer.cc", + "minidump_simple_string_dictionary_writer.h", + "minidump_stream_writer.cc", + "minidump_stream_writer.h", + "minidump_string_writer.cc", + "minidump_string_writer.h", + "minidump_system_info_writer.cc", + "minidump_system_info_writer.h", + "minidump_thread_id_map.cc", + "minidump_thread_id_map.h", + "minidump_thread_writer.cc", + "minidump_thread_writer.h", + "minidump_writable.cc", + "minidump_writable.h", + "minidump_writer_util.cc", + "minidump_writer_util.h", + ] +} diff --git a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn new file mode 100644 index 0000000..aa8443a --- /dev/null +++ b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn @@ -0,0 +1,103 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("snapshot") { + deps = [ + "../client", + "../compat", + "../util", + "//base", + ] + + include_dirs = [ ".." ] + + if (is_win) { + cflags = [ "/wd4201" ] + libs = [ "powrprof.lib" ] + } + + sources = [ + "cpu_architecture.h", + "cpu_context.cc", + "cpu_context.h", + "crashpad_info_client_options.cc", + "crashpad_info_client_options.h", + "exception_snapshot.h", + "handle_snapshot.cc", + "handle_snapshot.h", + "mac/cpu_context_mac.cc", + "mac/cpu_context_mac.h", + "mac/exception_snapshot_mac.cc", + "mac/exception_snapshot_mac.h", + "mac/mach_o_image_annotations_reader.cc", + "mac/mach_o_image_annotations_reader.h", + "mac/mach_o_image_reader.cc", + "mac/mach_o_image_reader.h", + "mac/mach_o_image_segment_reader.cc", + "mac/mach_o_image_segment_reader.h", + "mac/mach_o_image_symbol_table_reader.cc", + "mac/mach_o_image_symbol_table_reader.h", + "mac/memory_snapshot_mac.cc", + "mac/memory_snapshot_mac.h", + "mac/module_snapshot_mac.cc", + "mac/module_snapshot_mac.h", + "mac/process_reader.cc", + "mac/process_reader.h", + "mac/process_snapshot_mac.cc", + "mac/process_snapshot_mac.h", + "mac/process_types.cc", + "mac/process_types.h", + "mac/process_types/all.proctype", + "mac/process_types/crashpad_info.proctype", + "mac/process_types/crashreporterclient.proctype", + "mac/process_types/custom.cc", + "mac/process_types/dyld_images.proctype", + "mac/process_types/flavors.h", + "mac/process_types/internal.h", + "mac/process_types/loader.proctype", + "mac/process_types/nlist.proctype", + "mac/process_types/traits.h", + "mac/system_snapshot_mac.cc", + "mac/system_snapshot_mac.h", + "mac/thread_snapshot_mac.cc", + "mac/thread_snapshot_mac.h", + "memory_snapshot.h", + "minidump/minidump_simple_string_dictionary_reader.cc", + "minidump/minidump_simple_string_dictionary_reader.h", + "minidump/minidump_string_list_reader.cc", + "minidump/minidump_string_list_reader.h", + "minidump/minidump_string_reader.cc", + "minidump/minidump_string_reader.h", + "minidump/module_snapshot_minidump.cc", + "minidump/module_snapshot_minidump.h", + "minidump/process_snapshot_minidump.cc", + "minidump/process_snapshot_minidump.h", + "module_snapshot.h", + "process_snapshot.h", + "system_snapshot.h", + "thread_snapshot.h", + "win/cpu_context_win.cc", + "win/cpu_context_win.h", + "win/exception_snapshot_win.cc", + "win/exception_snapshot_win.h", + "win/memory_map_region_snapshot_win.cc", + "win/memory_map_region_snapshot_win.h", + "win/memory_snapshot_win.cc", + "win/memory_snapshot_win.h", + "win/module_snapshot_win.cc", + "win/module_snapshot_win.h", + "win/pe_image_annotations_reader.cc", + "win/pe_image_annotations_reader.h", + "win/pe_image_reader.cc", + "win/pe_image_reader.h", + "win/process_reader_win.cc", + "win/process_reader_win.h", + "win/process_snapshot_win.cc", + "win/process_snapshot_win.h", + "win/system_snapshot_win.cc", + "win/system_snapshot_win.h", + "win/thread_snapshot_win.cc", + "win/thread_snapshot_win.h", + ] +} diff --git a/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn index 3835d51..3edcfda 100644 --- a/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn @@ -4,7 +4,7 @@ source_set("getopt") { sources = [ - "getopt.c", + "getopt.cc", "getopt.h", ] } diff --git a/build/secondary/third_party/crashpad/crashpad/tools/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/tools/BUILD.gn new file mode 100644 index 0000000..94fe0b4 --- /dev/null +++ b/build/secondary/third_party/crashpad/crashpad/tools/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("tool_support") { + deps = [ + "//base", + ] + + include_dirs = [ ".." ] + + if (is_win) { + cflags = [ "/wd4201" ] + } + + sources = [ + "tool_support.cc", + "tool_support.h", + ] +} diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn index 0fe15b6..9429597 100644 --- a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn @@ -58,39 +58,6 @@ source_set("util") { "mac/service_management.h", "mac/xattr.cc", "mac/xattr.h", - "mach/child_port_handshake.cc", - "mach/child_port_handshake.h", - "mach/child_port_server.cc", - "mach/child_port_server.h", - "mach/child_port_types.h", - "mach/composite_mach_message_server.cc", - "mach/composite_mach_message_server.h", - "mach/exc_client_variants.cc", - "mach/exc_client_variants.h", - "mach/exc_server_variants.cc", - "mach/exc_server_variants.h", - "mach/exception_behaviors.cc", - "mach/exception_behaviors.h", - "mach/exception_ports.cc", - "mach/exception_ports.h", - "mach/exception_types.cc", - "mach/exception_types.h", - "mach/mach_extensions.cc", - "mach/mach_extensions.h", - "mach/mach_message.cc", - "mach/mach_message.h", - "mach/mach_message_server.cc", - "mach/mach_message_server.h", - "mach/notify_server.cc", - "mach/notify_server.h", - "mach/scoped_task_suspend.cc", - "mach/scoped_task_suspend.h", - "mach/symbolic_constants_mach.cc", - "mach/symbolic_constants_mach.h", - "mach/task_for_pid.cc", - "mach/task_for_pid.h", - "mach/task_memory.cc", - "mach/task_memory.h", "misc/clock.h", "misc/clock_mac.cc", "misc/clock_posix.cc", @@ -101,6 +68,8 @@ source_set("util") { "misc/initialization_state_dcheck.h", "misc/pdb_structures.cc", "misc/pdb_structures.h", + "misc/random_string.cc", + "misc/random_string.h", "misc/scoped_forbid_return.cc", "misc/scoped_forbid_return.h", "misc/symbolic_constants_common.h", @@ -159,12 +128,16 @@ source_set("util") { "win/capture_context.asm", "win/capture_context.h", "win/checked_win_address_range.h", + "win/command_line.cc", + "win/command_line.h", "win/critical_section_with_debug_info.cc", "win/critical_section_with_debug_info.h", "win/exception_handler_server.cc", "win/exception_handler_server.h", "win/get_function.cc", "win/get_function.h", + "win/handle.cc", + "win/handle.h", "win/module_version.cc", "win/module_version.h", "win/nt_internals.cc", @@ -178,6 +151,8 @@ source_set("util") { "win/registration_protocol_win.h", "win/scoped_handle.cc", "win/scoped_handle.h", + "win/scoped_local_alloc.cc", + "win/scoped_local_alloc.h", "win/scoped_process_suspend.cc", "win/scoped_process_suspend.h", "win/time.cc", @@ -185,6 +160,45 @@ source_set("util") { "win/xp_compat.h", ] + if (is_mac) { + # mach/ are not globally filtered. + sources += [ + "mach/child_port_handshake.cc", + "mach/child_port_handshake.h", + "mach/child_port_server.cc", + "mach/child_port_server.h", + "mach/child_port_types.h", + "mach/composite_mach_message_server.cc", + "mach/composite_mach_message_server.h", + "mach/exc_client_variants.cc", + "mach/exc_client_variants.h", + "mach/exc_server_variants.cc", + "mach/exc_server_variants.h", + "mach/exception_behaviors.cc", + "mach/exception_behaviors.h", + "mach/exception_ports.cc", + "mach/exception_ports.h", + "mach/exception_types.cc", + "mach/exception_types.h", + "mach/mach_extensions.cc", + "mach/mach_extensions.h", + "mach/mach_message.cc", + "mach/mach_message.h", + "mach/mach_message_server.cc", + "mach/mach_message_server.h", + "mach/notify_server.cc", + "mach/notify_server.h", + "mach/scoped_task_suspend.cc", + "mach/scoped_task_suspend.h", + "mach/symbolic_constants_mach.cc", + "mach/symbolic_constants_mach.h", + "mach/task_for_pid.cc", + "mach/task_for_pid.h", + "mach/task_memory.cc", + "mach/task_memory.h", + ] + } + # Include files from here and generated files starting with "util". include_dirs = [ "..", @@ -203,6 +217,8 @@ source_set("util") { "rpcrt4.lib", "winhttp.lib", ] + cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union. + # TODO(GYP) UseSafeExceptionHandlers masm rule. } else if (is_mac) { sources += get_target_outputs(":mig") diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 161cf0d..33f9136 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn @@ -158,6 +158,7 @@ if (!is_android) { "//content/public/common:static_switches", "//crypto", "//sandbox", + "//third_party/crashpad/crashpad/handler:handler_lib", "//ui/gfx", "//win8/delegate_execute", "//win8/metro_driver", @@ -404,6 +405,8 @@ if (is_mac || is_win) { shared_library("chrome_child") { sources = [ + "app/chrome_crash_reporter_client.cc", + "app/chrome_crash_reporter_client.h", "app/chrome_main.cc", "app/chrome_main_delegate.cc", "app/chrome_main_delegate.h", @@ -421,6 +424,8 @@ if (is_mac || is_win) { "//base/allocator", "//build/config/sanitizers:deps", "//chrome/browser/policy:path_parser", + "//components/browser_watcher:browser_watcher_client", + "//components/crash/content/app", "//content/public/app:child", ] diff --git a/chrome/app/DEPS b/chrome/app/DEPS index cd3a112..f306bcb 100644 --- a/chrome/app/DEPS +++ b/chrome/app/DEPS @@ -30,4 +30,5 @@ include_rules = [ "+remoting/client/plugin", "+sandbox", "+syzygy/kasko/api", + "+third_party/crashpad/crashpad", ] diff --git a/chrome/app/chrome_crash_reporter_client.cc b/chrome/app/chrome_crash_reporter_client.cc index 49c8c49..2663a08 100644 --- a/chrome/app/chrome_crash_reporter_client.cc +++ b/chrome/app/chrome_crash_reporter_client.cc @@ -292,17 +292,7 @@ bool ChromeCrashReporterClient::GetCrashDumpLocation( } size_t ChromeCrashReporterClient::RegisterCrashKeys() { - // Note: On Windows this only affects the EXE. A separate invocation from - // child_process_logging_win.cc registers crash keys for Chrome.dll. -#if defined(OS_WIN) && defined(COMPONENT_BUILD) - // On Windows, this is not called in a component build, as in that case a - // single copy of 'base' is shared by the EXE and the various DLLs, and that - // copy is configured by child_process_logging_win.cc. - NOTREACHED(); - return 0; -#else return crash_keys::RegisterChromeCrashKeys(); -#endif } bool ChromeCrashReporterClient::IsRunningUnattended() { diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc index e3e1754..cf91743 100644 --- a/chrome/app/chrome_exe_main_win.cc +++ b/chrome/app/chrome_exe_main_win.cc @@ -7,12 +7,14 @@ #include <shellscalingapi.h> #include <tchar.h> +#include <algorithm> #include <string> #include "base/at_exit.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/logging.h" +#include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/win/windows_version.h" #include "chrome/app/main_dll_loader_win.h" @@ -22,7 +24,9 @@ #include "chrome/common/chrome_switches.h" #include "chrome_elf/chrome_elf_main.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" +#include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" +#include "third_party/crashpad/crashpad/handler/handler_main.h" #include "ui/gfx/win/dpi.h" namespace { @@ -121,6 +125,35 @@ void SwitchToLFHeap() { } } +bool RunAsCrashpadHandler(wchar_t* command_line, int* rc) { + const base::CommandLine cmdline = base::CommandLine::FromString(command_line); + if (cmdline.GetSwitchValueASCII(switches::kProcessType) == + switches::kCrashpadHandler) { + std::vector<base::string16> argv = cmdline.argv(); + base::string16 process_type = + L"--" + base::UTF8ToUTF16(switches::kProcessType) + L"="; + argv.erase(std::remove_if(argv.begin(), argv.end(), + [&process_type](const base::string16& str) { + return str.compare(0, process_type.size(), + process_type) == 0; + }), + argv.end()); + + scoped_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]); + std::vector<std::string> storage; + storage.reserve(argv.size()); + for (size_t i = 0; i < argv.size(); ++i) { + storage.push_back(base::UTF16ToUTF8(argv[i])); + argv_as_utf8[i] = &storage[i][0]; + } + argv_as_utf8[argv.size()] = nullptr; + *rc = crashpad::HandlerMain(static_cast<int>(argv.size()), + argv_as_utf8.get()); + return true; + } + return false; +} + } // namespace #if !defined(WIN_CONSOLE_APP) @@ -129,6 +162,10 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) { int main() { HINSTANCE instance = GetModuleHandle(NULL); #endif + int rc; + if (RunAsCrashpadHandler(GetCommandLine(), &rc)) + return rc; + SwitchToLFHeap(); startup_metric_utils::RecordExeMainEntryPointTime(base::Time::Now()); @@ -153,7 +190,7 @@ int main() { // Load and launch the chrome dll. *Everything* happens inside. VLOG(1) << "About to load main DLL."; MainDllLoader* loader = MakeMainDllLoader(); - int rc = loader->Launch(instance); + rc = loader->Launch(instance); loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded(); delete loader; return rc; diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index cb27994..eef47b8 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc @@ -20,6 +20,7 @@ #include "base/time/time.h" #include "base/trace_event/trace_event_impl.h" #include "build/build_config.h" +#include "chrome/app/chrome_crash_reporter_client.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/defaults.h" #include "chrome/common/channel_info.h" @@ -40,6 +41,7 @@ #include "chrome/utility/chrome_content_utility_client.h" #include "components/component_updater/component_updater_paths.h" #include "components/content_settings/core/common/content_settings_pattern.h" +#include "components/crash/content/app/crash_reporter_client.h" #include "components/version_info/version_info.h" #include "content/public/common/content_client.h" #include "content/public/common/content_paths.h" @@ -55,6 +57,7 @@ #include "chrome/app/close_handle_hook_win.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/v8_breakpad_support_win.h" +#include "components/crash/content/app/crashpad.h" #include "sandbox/win/src/sandbox.h" #include "ui/base/resource/resource_bundle_win.h" #endif @@ -64,7 +67,7 @@ #include "chrome/app/chrome_main_mac.h" #include "chrome/browser/mac/relauncher.h" #include "chrome/common/mac/cfbundle_blocker.h" -#include "components/crash/content/app/crashpad_mac.h" +#include "components/crash/content/app/crashpad.h" #include "components/crash/core/common/objc_zombie.h" #include "ui/base/l10n/l10n_util_mac.h" #endif @@ -72,8 +75,6 @@ #if defined(OS_POSIX) #include <locale.h> #include <signal.h> -#include "chrome/app/chrome_crash_reporter_client.h" -#include "components/crash/content/app/crash_reporter_client.h" #endif #if !defined(DISABLE_NACL) && defined(OS_LINUX) @@ -145,7 +146,7 @@ base::LazyInstance<ChromeContentBrowserClient> g_chrome_content_browser_client = LAZY_INSTANCE_INITIALIZER; #endif -#if defined(OS_POSIX) +#if defined(OS_POSIX) || defined(OS_WIN) base::LazyInstance<ChromeCrashReporterClient>::Leaky g_chrome_crash_client = LAZY_INSTANCE_INITIALIZER; #endif @@ -448,7 +449,6 @@ bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) { const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - #if defined(OS_WIN) // Browser should not be sandboxed. const bool is_browser = !command_line.HasSwitch(switches::kProcessType); @@ -665,7 +665,7 @@ void ChromeMainDelegate::PreSandboxStartup() { std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType); -#if defined(OS_POSIX) +#if defined(OS_POSIX) || defined(OS_WIN) crash_reporter::SetCrashReporterClient(g_chrome_crash_client.Pointer()); #endif @@ -680,6 +680,16 @@ void ChromeMainDelegate::PreSandboxStartup() { #endif #if defined(OS_WIN) + // TODO(scottmg): It would be nice to do this earlier to catch early crashes, + // perhaps as early as WinMain in chrome.exe. This would require some code + // restructuring to have paths and command lines set up, and also to handle + // having some of the code live in chrome.exe, while having the database be + // accessed by browser code in chrome.dll (to get a list of uploaded crashes + // for chrome://crashes). + crash_reporter::InitializeCrashpad(process_type.empty(), process_type); +#endif // OS_WIN + +#if defined(OS_WIN) child_process_logging::Init(); #endif #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index 39dcf25..a6036e8 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc @@ -22,6 +22,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/platform_thread.h" #include "base/trace_event/trace_event.h" +#include "base/win/metro.h" #include "base/win/scoped_handle.h" #include "base/win/windows_version.h" #include "chrome/app/chrome_crash_reporter_client.h" @@ -41,8 +42,8 @@ #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/module_util_win.h" #include "chrome/installer/util/util_constants.h" -#include "components/crash/content/app/breakpad_win.h" #include "components/crash/content/app/crash_reporter_client.h" +#include "components/crash/content/app/crashpad.h" #include "components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h" #include "content/public/app/sandbox_helper_win.h" #include "content/public/common/content_switches.h" @@ -54,9 +55,6 @@ typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*); typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)(); -base::LazyInstance<ChromeCrashReporterClient>::Leaky g_chrome_crash_client = - LAZY_INSTANCE_INITIALIZER; - // Loads |module| after setting the CWD to |module|'s directory. Returns a // reference to the loaded module on success, or null on error. HMODULE LoadModuleWithDirectory(const base::FilePath& module, bool pre_read) { @@ -100,11 +98,6 @@ void ClearDidRun(const base::FilePath& dll_path) { GoogleUpdateSettings::UpdateDidRunState(false, system_level); } -bool InMetroMode() { - return (wcsstr( - ::GetCommandLineW(), L" -ServerName:DefaultBrowserServer") != nullptr); -} - typedef int (*InitMetro)(); } // namespace @@ -112,7 +105,7 @@ typedef int (*InitMetro)(); //============================================================================= MainDllLoader::MainDllLoader() - : dll_(nullptr), metro_mode_(InMetroMode()) { + : dll_(nullptr), metro_mode_(base::win::IsMetroProcess()) { } MainDllLoader::~MainDllLoader() { @@ -224,18 +217,6 @@ int MainDllLoader::Launch(HINSTANCE instance) { sandbox::SandboxInterfaceInfo sandbox_info = {0}; content::InitializeSandboxInfo(&sandbox_info); - crash_reporter::SetCrashReporterClient(g_chrome_crash_client.Pointer()); - bool exit_now = true; - if (process_type_.empty()) { - if (breakpad::ShowRestartDialogIfCrashed(&exit_now)) { - // We restarted because of a previous crash. Ask user if we should - // Relaunch. Only for the browser process. See crbug.com/132119. - if (exit_now) - return content::RESULT_CODE_NORMAL_EXIT; - } - } - breakpad::InitCrashReporter(process_type_); - dll_ = Load(&version, &file); if (!dll_) return chrome::RESULT_CODE_MISSING_DATA; @@ -248,12 +229,6 @@ int MainDllLoader::Launch(HINSTANCE instance) { reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain")); int rc = chrome_main(instance, &sandbox_info); rc = OnBeforeExit(rc, file); - // Sandboxed processes close some system DLL handles after lockdown so ignore - // EXCEPTION_INVALID_HANDLE generated on Windows 10 during shutdown of these - // processes. - // TODO(wfh): Check whether MS have fixed this in Win10 RTM. crbug.com/456193 - if (base::win::GetVersion() >= base::win::VERSION_WIN10) - breakpad::ConsumeInvalidHandleExceptions(); return rc; } @@ -295,7 +270,13 @@ void ChromeDllLoader::OnBeforeLaunch(const std::string& process_type, RecordDidRun(dll_path); // Launch the watcher process if stats collection consent has been granted. - if (g_chrome_crash_client.Get().GetCollectStatsConsent()) { +#if defined(GOOGLE_CHROME_BUILD) + const bool stats_collection_consent = + GoogleUpdateSettings::GetCollectStatsConsent(); +#else + const bool stats_collection_consent = false; +#endif + if (stats_collection_consent) { base::FilePath exe_path; if (PathService::Get(base::FILE_EXE, &exe_path)) { chrome_watcher_client_.reset(new ChromeWatcherClient( diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 315a95e..41f867fc 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn @@ -612,7 +612,7 @@ source_set("browser") { } else { sources -= [ "password_manager/password_store_x.cc" ] } - if (is_posix && !is_mac && !is_ios) { + if ((is_posix && !is_mac && !is_ios) || is_win) { sources += [ "//chrome/app/chrome_crash_reporter_client.cc", "//chrome/app/chrome_crash_reporter_client.h", diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm index 5423f6d..4b8d76b 100644 --- a/chrome/browser/chrome_browser_main_mac.mm +++ b/chrome/browser/chrome_browser_main_mac.mm @@ -24,7 +24,7 @@ #include "chrome/browser/ui/app_list/app_list_service.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" -#include "components/crash/content/app/crashpad_mac.h" +#include "components/crash/content/app/crashpad.h" #include "components/metrics/metrics_service.h" #include "content/public/common/main_function_params.h" #include "content/public/common/result_codes.h" diff --git a/chrome/browser/crash_upload_list.cc b/chrome/browser/crash_upload_list.cc index 82e17d4..9e30d84 100644 --- a/chrome/browser/crash_upload_list.cc +++ b/chrome/browser/crash_upload_list.cc @@ -11,10 +11,8 @@ #include "chrome/common/chrome_paths.h" #include "content/public/browser/browser_thread.h" -#if defined(OS_WIN) -#include "chrome/browser/crash_upload_list_win.h" -#elif defined(OS_MACOSX) -#include "chrome/browser/crash_upload_list_mac.h" +#if defined(OS_MACOSX) || defined(OS_WIN) +#include "chrome/browser/crash_upload_list_crashpad.h" #endif scoped_refptr<CrashUploadList> CreateCrashUploadList( @@ -23,12 +21,9 @@ scoped_refptr<CrashUploadList> CreateCrashUploadList( PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path); base::FilePath upload_log_path = crash_dir_path.AppendASCII(CrashUploadList::kReporterLogFilename); -#if defined(OS_WIN) - return new CrashUploadListWin(delegate, upload_log_path, - content::BrowserThread::GetBlockingPool()); -#elif defined(OS_MACOSX) - return new CrashUploadListMac(delegate, upload_log_path, - content::BrowserThread::GetBlockingPool()); +#if defined(OS_MACOSX) || defined(OS_WIN) + return new CrashUploadListCrashpad(delegate, upload_log_path, + content::BrowserThread::GetBlockingPool()); #else return new CrashUploadList(delegate, upload_log_path, content::BrowserThread::GetBlockingPool()); diff --git a/chrome/browser/crash_upload_list_mac.cc b/chrome/browser/crash_upload_list_crashpad.cc index 8148847..a2a4bbd 100644 --- a/chrome/browser/crash_upload_list_mac.cc +++ b/chrome/browser/crash_upload_list_crashpad.cc @@ -2,23 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/crash_upload_list_mac.h" +#include "chrome/browser/crash_upload_list_crashpad.h" #include "base/threading/sequenced_worker_pool.h" #include "base/time/time.h" -#include "components/crash/content/app/crashpad_mac.h" +#include "components/crash/content/app/crashpad.h" -CrashUploadListMac::CrashUploadListMac( +CrashUploadListCrashpad::CrashUploadListCrashpad( Delegate* delegate, const base::FilePath& upload_log_path, const scoped_refptr<base::SequencedWorkerPool>& worker_pool) - : CrashUploadList(delegate, upload_log_path, worker_pool) { -} + : CrashUploadList(delegate, upload_log_path, worker_pool) {} -CrashUploadListMac::~CrashUploadListMac() { -} +CrashUploadListCrashpad::~CrashUploadListCrashpad() {} -void CrashUploadListMac::LoadUploadList() { +void CrashUploadListCrashpad::LoadUploadList() { std::vector<crash_reporter::UploadedReport> uploaded_reports; crash_reporter::GetUploadedReports(&uploaded_reports); @@ -28,7 +26,6 @@ void CrashUploadListMac::LoadUploadList() { AppendUploadInfo( UploadInfo(uploaded_report.remote_id, base::Time::FromTimeT(uploaded_report.creation_time), - uploaded_report.local_id, - base::Time())); + uploaded_report.local_id, base::Time())); } } diff --git a/chrome/browser/crash_upload_list_mac.h b/chrome/browser/crash_upload_list_crashpad.h index f7fb4f1..d884640 100644 --- a/chrome/browser/crash_upload_list_mac.h +++ b/chrome/browser/crash_upload_list_crashpad.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CRASH_UPLOAD_LIST_MAC_H_ -#define CHROME_BROWSER_CRASH_UPLOAD_LIST_MAC_H_ +#ifndef CHROME_BROWSER_CRASH_UPLOAD_LIST_CRASHPAD_H_ +#define CHROME_BROWSER_CRASH_UPLOAD_LIST_CRASHPAD_H_ #include "base/macros.h" #include "components/upload_list/crash_upload_list.h" @@ -15,23 +15,23 @@ class SequencedWorkerPool; // A CrashUploadList that retrieves the list of uploaded reports from the // Crashpad database. -class CrashUploadListMac : public CrashUploadList { +class CrashUploadListCrashpad : public CrashUploadList { public: // The |upload_log_path| argument is unused. It is only accepted because the // base class constructor requires it, although it is entirely unused with // LoadUploadList() being overridden. - CrashUploadListMac( + CrashUploadListCrashpad( Delegate* delegate, const base::FilePath& upload_log_path, const scoped_refptr<base::SequencedWorkerPool>& worker_pool); protected: - ~CrashUploadListMac() override; + ~CrashUploadListCrashpad() override; // Called on a blocking pool thread. void LoadUploadList() override; - DISALLOW_COPY_AND_ASSIGN(CrashUploadListMac); + DISALLOW_COPY_AND_ASSIGN(CrashUploadListCrashpad); }; -#endif // CHROME_BROWSER_CRASH_UPLOAD_LIST_MAC_H_ +#endif // CHROME_BROWSER_CRASH_UPLOAD_LIST_CRASHPAD_H_ diff --git a/chrome/browser/crash_upload_list_win.cc b/chrome/browser/crash_upload_list_win.cc deleted file mode 100644 index a85e321..0000000 --- a/chrome/browser/crash_upload_list_win.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/crash_upload_list_win.h" - -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" -#include "base/threading/sequenced_worker_pool.h" - -CrashUploadListWin::CrashUploadListWin( - Delegate* delegate, - const base::FilePath& upload_log_path, - const scoped_refptr<base::SequencedWorkerPool>& worker_pool) - : CrashUploadList(delegate, upload_log_path, worker_pool) {} - -void CrashUploadListWin::LoadUploadList() { - std::vector<uint8> buffer(1024); - HANDLE event_log = OpenEventLog(NULL, L"Application"); - if (event_log) { - ClearUploads(); - while (true) { - DWORD bytes_read; - DWORD bytes_needed; - BOOL success = - ReadEventLog(event_log, - EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, - 0, - &buffer[0], - buffer.size(), - &bytes_read, - &bytes_needed); - if (success) { - DWORD record_offset = 0; - // The ReadEventLog() API docs imply, but do not explicitly state that - // partial records will not be returned. Use DCHECK() to affirm this. - while (record_offset < bytes_read) { - DCHECK(record_offset + sizeof(EVENTLOGRECORD) <= bytes_read); - EVENTLOGRECORD* record = (EVENTLOGRECORD*)&buffer[record_offset]; - DCHECK(record_offset + record->Length <= bytes_read); - if (IsPossibleCrashLogRecord(record)) - ProcessPossibleCrashLogRecord(record); - record_offset += record->Length; - } - } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Resize buffer to the required minimum size. - buffer.resize(bytes_needed); - } else { - // Stop on any other error, including the expected case - // of ERROR_HANDLE_EOF. - DCHECK(GetLastError() == ERROR_HANDLE_EOF); - break; - } - } - CloseEventLog(event_log); - } -} - -CrashUploadListWin::~CrashUploadListWin() { -} - -bool CrashUploadListWin::IsPossibleCrashLogRecord( - EVENTLOGRECORD* record) const { - LPWSTR provider_name = (LPWSTR)((uint8*)record + sizeof(EVENTLOGRECORD)); - return !wcscmp(L"Chrome", provider_name) && - record->EventType == EVENTLOG_INFORMATION_TYPE && - record->NumStrings >= 1; -} - -void CrashUploadListWin::ProcessPossibleCrashLogRecord(EVENTLOGRECORD* record) { - // Add the crash if the message matches the expected pattern. - const std::wstring pattern_prefix(L"Id="); - const std::wstring pattern_suffix(L"."); - std::wstring message((LPWSTR)((uint8*)record + record->StringOffset)); - size_t start_index = message.find(pattern_prefix); - if (start_index != std::wstring::npos) { - start_index += pattern_prefix.size(); - size_t end_index = message.find(pattern_suffix, start_index); - if (end_index != std::wstring::npos) { - std::wstring crash_id = - message.substr(start_index, end_index - start_index); - AppendUploadInfo( - UploadInfo(base::SysWideToUTF8(crash_id), - base::Time::FromDoubleT(record->TimeGenerated))); - } - } -} diff --git a/chrome/browser/crash_upload_list_win.h b/chrome/browser/crash_upload_list_win.h deleted file mode 100644 index 40d8ccf..0000000 --- a/chrome/browser/crash_upload_list_win.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CRASH_UPLOAD_LIST_WIN_H_ -#define CHROME_BROWSER_CRASH_UPLOAD_LIST_WIN_H_ - -#include "base/macros.h" -#include "components/upload_list/crash_upload_list.h" - -namespace base { -class FilePath; -class SequencedWorkerPool; -} - -// A CrashUploadList that retrieves the list of reported crashes -// from the Windows Event Log. -class CrashUploadListWin : public CrashUploadList { - public: - CrashUploadListWin( - Delegate* delegate, - const base::FilePath& upload_log_path, - const scoped_refptr<base::SequencedWorkerPool>& worker_pool); - - protected: - // Loads the list of crashes from the Windows Event Log. - void LoadUploadList() override; - - private: - ~CrashUploadListWin() override; - - // Returns whether the event record is likely a Chrome crash log. - bool IsPossibleCrashLogRecord(EVENTLOGRECORD* record) const; - - // Parses the event record and adds it to the crash list. - void ProcessPossibleCrashLogRecord(EVENTLOGRECORD* record); - - DISALLOW_COPY_AND_ASSIGN(CrashUploadListWin); -}; - -#endif // CHROME_BROWSER_CRASH_UPLOAD_LIST_WIN_H_ diff --git a/chrome/browser/google/google_update_settings_posix.cc b/chrome/browser/google/google_update_settings_posix.cc index 8cfadc8..c75f806 100644 --- a/chrome/browser/google/google_update_settings_posix.cc +++ b/chrome/browser/google/google_update_settings_posix.cc @@ -13,7 +13,7 @@ #include "chrome/common/chrome_paths.h" #if defined(OS_MACOSX) -#include "components/crash/content/app/crashpad_mac.h" +#include "components/crash/content/app/crashpad.h" #endif namespace { diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d6df1df..bf1b664 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -428,10 +428,6 @@ 'browser/component_updater/swiftshader_component_installer.h', 'browser/crash_upload_list.cc', 'browser/crash_upload_list.h', - 'browser/crash_upload_list_mac.cc', - 'browser/crash_upload_list_mac.h', - 'browser/crash_upload_list_win.cc', - 'browser/crash_upload_list_win.h', 'browser/custom_handlers/protocol_handler_registry.cc', 'browser/custom_handlers/protocol_handler_registry.h', 'browser/custom_handlers/protocol_handler_registry_factory.cc', @@ -1345,6 +1341,8 @@ ], # Sources (generally "desktop OS importers") used only on Mac & Windows. 'chrome_browser_win_mac_sources': [ + 'browser/crash_upload_list_crashpad.cc', + 'browser/crash_upload_list_crashpad.h', 'browser/media_galleries/fileapi/file_path_watcher_util.cc', 'browser/media_galleries/fileapi/file_path_watcher_util.h', 'browser/media_galleries/fileapi/iapps_data_provider.cc', diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index 0ea9690..09c93d5 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -123,7 +123,9 @@ ], 'dependencies': [ '<@(chromium_browser_dependencies)', + '../components/components.gyp:crash_component', '../content/content.gyp:content_app_browser', + '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler', ], 'conditions': [ ['OS=="win"', { @@ -163,6 +165,8 @@ ], 'sources': [ 'app/chrome_dll.rc', + 'app/chrome_crash_reporter_client.cc', + 'app/chrome_crash_reporter_client.h', # ETW Manifest. '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest/chrome_events_win.rc', @@ -350,6 +354,8 @@ }, 'dependencies': [ '<@(chromium_child_dependencies)', + '../components/components.gyp:browser_watcher_client', + '../components/components.gyp:crash_component', '../content/content.gyp:content_app_child', 'chrome_version_resources', 'policy_path_parser', @@ -359,6 +365,8 @@ ], 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/chrome_version/chrome_dll_version.rc', + 'app/chrome_crash_reporter_client.cc', + 'app/chrome_crash_reporter_client.h', 'app/chrome_main.cc', 'app/chrome_main_delegate.cc', 'app/chrome_main_delegate.h', @@ -392,6 +400,11 @@ }], ] }], + ['OS=="win" and configuration_policy==1', { + 'dependencies': [ + '<(DEPTH)/components/components.gyp:policy', + ], + }], ['enable_plugins==1', { 'dependencies': [ '../pdf/pdf.gyp:pdf', diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index a2fa643..27bd63e 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi @@ -105,6 +105,7 @@ 'chrome_watcher', 'chrome_watcher_client', '../components/components.gyp:browser_watcher_client', + '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler_lib', ], 'conditions': [ ['kasko==1', { @@ -432,8 +433,6 @@ ], 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/chrome_version/chrome_exe_version.rc', - 'app/chrome_crash_reporter_client.cc', - 'app/chrome_crash_reporter_client.h', 'app/chrome_exe.rc', 'common/crash_keys.cc', 'common/crash_keys.h', diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi index e3bb386..7cfe686 100644 --- a/chrome/chrome_installer.gypi +++ b/chrome/chrome_installer.gypi @@ -220,7 +220,7 @@ '../chrome/common_constants.gyp:common_constants', '../chrome/common_constants.gyp:version_header', '../chrome_elf/chrome_elf.gyp:chrome_elf_constants', - '../components/components.gyp:crash_component', + '../components/components.gyp:crash_component_breakpad_to_be_deleted', '../rlz/rlz.gyp:rlz_lib', '../third_party/zlib/zlib.gyp:zlib', ], diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 23e66b3..7dc429b 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -2063,13 +2063,13 @@ 'include_dirs': [ '<(DEPTH)/third_party/wtl/include', ], - 'conditions': [ - ['use_aura==1', { - 'dependencies': [ - '../win8/win8.gyp:test_registrar_constants', - '../win8/win8.gyp:test_support_win8', - ], - }], + 'dependencies': [ + '../components/components.gyp:crash_component', + '../win8/win8.gyp:test_registrar_constants', + '../win8/win8.gyp:test_support_win8', + ], + 'sources': [ + 'app/chrome_crash_reporter_client.cc', ], }], ['OS=="win" or OS=="mac"', { diff --git a/chrome/common/child_process_logging_win.cc b/chrome/common/child_process_logging_win.cc index 9571701..4e3177c 100644 --- a/chrome/common/child_process_logging_win.cc +++ b/chrome/common/child_process_logging_win.cc @@ -16,57 +16,7 @@ namespace child_process_logging { -namespace { - -// exported in breakpad_win.cc: -// void __declspec(dllexport) __cdecl SetCrashKeyValueImpl. -typedef void (__cdecl *SetCrashKeyValue)(const wchar_t*, const wchar_t*); - -// exported in breakpad_win.cc: -// void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl. -typedef void (__cdecl *ClearCrashKeyValue)(const wchar_t*); - -void SetCrashKeyValueTrampoline(const base::StringPiece& key, - const base::StringPiece& value) { - static SetCrashKeyValue set_crash_key = NULL; - if (!set_crash_key) { - HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName); - if (!exe_module) - return; - set_crash_key = reinterpret_cast<SetCrashKeyValue>( - GetProcAddress(exe_module, "SetCrashKeyValueImpl")); - } - - if (set_crash_key) { - (set_crash_key)(base::UTF8ToWide(key).data(), - base::UTF8ToWide(value).data()); - } -} - -void ClearCrashKeyValueTrampoline(const base::StringPiece& key) { - static ClearCrashKeyValue clear_crash_key = NULL; - if (!clear_crash_key) { - HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName); - if (!exe_module) - return; - clear_crash_key = reinterpret_cast<ClearCrashKeyValue>( - GetProcAddress(exe_module, "ClearCrashKeyValueImpl")); - } - - if (clear_crash_key) - (clear_crash_key)(base::UTF8ToWide(key).data()); -} - -} // namespace - void Init() { - // Note: on other platforms, this is set up during Breakpad initialization, - // in ChromeBreakpadClient. But on Windows, that is before the DLL module is - // loaded, which is a prerequisite of the crash key system. - crash_keys::RegisterChromeCrashKeys(); - base::debug::SetCrashKeyReportingFunctions( - &SetCrashKeyValueTrampoline, &ClearCrashKeyValueTrampoline); - // This would be handled by BreakpadClient::SetCrashClientIdFromGUID(), but // because of the aforementioned issue, crash keys aren't ready yet at the // time of Breakpad initialization, load the client id backed up in Google diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc index f17ba29..66c7bf2 100644 --- a/chrome/common/chrome_paths.cc +++ b/chrome/common/chrome_paths.cc @@ -210,7 +210,7 @@ bool PathProvider(int key, base::FilePath* result) { if (!GetDefaultUserDataDirectory(&cur)) return false; #endif -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) || defined(OS_WIN) cur = cur.Append(FILE_PATH_LITERAL("Crashpad")); #else cur = cur.Append(FILE_PATH_LITERAL("Crash Reports")); diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index c4f324d..5cd5b8e 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -1238,6 +1238,14 @@ const char kRelauncherProcessDMGDevice[] = "dmg-device"; #endif // defined(OS_MACOSX) #if defined(OS_WIN) +// A process type (switches::kProcessType) that indicates chrome.exe is being +// launched as crashpad_handler. This is only used on Windows. We bundle the +// handler into chrome.exe on Windows because there is high probability of a +// "new" .exe being blocked or interfered with by application firewalls, AV +// software, etc. On other platforms, crashpad_handler is a standalone +// executable. +const char kCrashpadHandler[] = "crashpad-handler"; + // Fallback to XPS. By default connector uses CDD. const char kEnableCloudPrintXps[] = "enable-cloud-print-xps"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index ce53949..b8c5eb8 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -353,6 +353,7 @@ extern const char kRelauncherProcessDMGDevice[]; #endif // defined(OS_MACOSX) #if defined(OS_WIN) +extern const char kCrashpadHandler[]; extern const char kEnableCloudPrintXps[]; extern const char kEnableProfileShortcutManager[]; extern const char kForceDesktop[]; diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc index ad3fb13..1a670fb 100644 --- a/chrome/common/crash_keys.cc +++ b/chrome/common/crash_keys.cc @@ -87,7 +87,7 @@ size_t RegisterChromeCrashKeys() { // The following keys may be chunked by the underlying crash logging system, // but ultimately constitute a single key-value pair. base::debug::CrashKey fixed_keys[] = { -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) || defined(OS_WIN) { kMetricsClientId, kSmallSize }, #else { kClientId, kSmallSize }, diff --git a/chrome/installer/setup/BUILD.gn b/chrome/installer/setup/BUILD.gn index a2b863b..e600847c 100644 --- a/chrome/installer/setup/BUILD.gn +++ b/chrome/installer/setup/BUILD.gn @@ -24,6 +24,8 @@ if (is_win) { ":lib", "//base/allocator", "//build/config/sanitizers:deps", + "//components/crash/content/app", + "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted", ] } @@ -56,6 +58,7 @@ if (is_win) { "//chrome/installer/util", "//chrome_elf:constants", "//components/crash/content/app", + "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted", "//components/crash/content/app:lib", "//components/crash/core/common", "//courgette:courgette_lib", diff --git a/chrome/interactive_ui_tests.isolate b/chrome/interactive_ui_tests.isolate index d5af58e..5aa6cb5 100644 --- a/chrome/interactive_ui_tests.isolate +++ b/chrome/interactive_ui_tests.isolate @@ -95,6 +95,7 @@ 'variables': { 'files': [ '<(PRODUCT_DIR)/chrome_elf.dll', + '<(PRODUCT_DIR)/crashpad_handler.exe', '<(PRODUCT_DIR)/d3dcompiler_47.dll', '<(PRODUCT_DIR)/libEGL.dll', '<(PRODUCT_DIR)/libGLESv2.dll', diff --git a/components/crash.gypi b/components/crash.gypi index 21af3bc..d12d5b4 100644 --- a/components/crash.gypi +++ b/components/crash.gypi @@ -94,34 +94,35 @@ # crash_component. # # This is a temporary base target that is depended on by both - # crash_component and crash_component_breakpad_mac_to_be_deleted. It - # provides everything common to both of those targets. For a short period, - # there are two Mac crash component implementations. The new one uses a - # Crashpad implementation and is used by Chrome. The old one uses a - # Breakpad implementation and is used by content_shell. Consumers should - # depend on the desired target. All three targets behave identically on - # non-Mac. When content_shell and any other consumers are migrated to the - # Crashpad implementation on Mac, crash_component will merge back into - # this target, crash_component_non_mac, which will be renamed - # crash_component. crash_component_breakpad_mac_to_be_deleted will be - # deleted. + # crash_component and crash_component_breakpad_to_be_deleted. It + # provides everything common to both of those targets. For a short + # period, there are two Mac and Windows crash component + # implementations. The new one uses a Crashpad implementation and is + # used by Chrome. The old one uses a Breakpad implementation and is + # used by content_shell. Consumers should depend on the desired + # target. All three targets behave identically on non-Mac/-Windows. + # When content_shell and any other consumers are migrated to the + # Crashpad implementation on Mac/Windows, crash_component will merge + # back into this target, crash_component_non_mac_win, which will be + # renamed crash_component. crash_component_breakpad_to_be_deleted will + # be deleted. # # While this situation exists: # # Do not depend on this target directly! Depend on - # crash_component_breakpad_mac_to_be_deleted for old Breakpad behavior on + # crash_component_breakpad_to_be_deleted for old Breakpad behavior on # all platforms, or preferably, depend on crash_component to get Breakpad - # everywhere except for Mac, where you will get Crashpad. + # everywhere except for Mac and Windows, where you will get Crashpad. # # GN version: //components/crash/content/app:app_non_mac - 'target_name': 'crash_component_non_mac', + 'target_name': 'crash_component_non_mac_win', 'variables': { 'conditions': [ ['OS == "ios" or OS == "mac"', { # On IOS there are no files compiled into the library, and we # can't have libraries with zero objects. - # For now, the same applies to Mac OS X, until this target merges - # with crash_component. + # For now, the same applies to Mac OS X, until this target + # merges with crash_component. 'crash_component_target_type%': 'none', }, { 'crash_component_target_type%': 'static_library', @@ -133,8 +134,6 @@ 'crash/content/app/breakpad_linux.cc', 'crash/content/app/breakpad_linux.h', 'crash/content/app/breakpad_linux_impl.h', - 'crash/content/app/breakpad_win.cc', - 'crash/content/app/breakpad_win.h', 'crash/content/app/hard_error_handler_win.cc', 'crash/content/app/hard_error_handler_win.h', ], @@ -178,17 +177,17 @@ # GN version: //components/crash/content/app # TODO(mark): https://crbug.com/466890: merge this target with - # crash_component_non_mac. + # crash_component_non_mac_win. # # Most of this target is actually in its dependency, - # crash_component_non_mac. See the comment in that target for an + # crash_component_non_mac_win. See the comment in that target for an # explanation for the split. The split is temporary and the two targets # will be unified again soon. 'target_name': 'crash_component', 'variables': { 'conditions': [ - ['OS != "mac" ', { - # There are no source files on any platform but Mac OS X. + ['OS != "mac" and OS != "win"', { + # There are no source files except on Mac OS X and Windows. 'crash_component_target_type%': 'none', }, { 'crash_component_target_type%': 'static_library', @@ -197,17 +196,19 @@ }, 'type': '<(crash_component_target_type)', 'sources': [ - 'crash/content/app/crashpad_mac.h', + 'crash/content/app/crashpad.cc', + 'crash/content/app/crashpad.h', 'crash/content/app/crashpad_mac.mm', + 'crash/content/app/crashpad_win.cc', ], 'dependencies': [ - 'crash_component_non_mac', + 'crash_component_non_mac_win', 'crash_component_lib', '../base/base.gyp:base', ], 'defines': ['CRASH_IMPLEMENTATION'], 'conditions': [ - ['OS=="mac"', { + ['OS=="mac" or OS=="win"', { 'dependencies': [ '../third_party/crashpad/crashpad/client/client.gyp:crashpad_client', ], @@ -217,18 +218,20 @@ { # TODO(mark): https://crbug.com/466890: remove this target. # - # This is a temporary target provided for Mac Breakpad users that have not - # yet migrated to Crashpad (namely content_shell). This target will be - # removed shortly and all consumers will be expected to use Crashpad as - # the Mac crash-reporting client. See the comment in the - # crash_component_non_mac target for more details. + # This is a temporary target provided for Mac and Windows Breakpad + # users that have not yet migrated to Crashpad (namely content_shell). + # This target will be removed shortly and all consumers will be + # expected to use Crashpad as the Mac and Windows crash-reporting + # client. See the comment in the crash_component_non_mac_win target + # for more details. # # GN version: //components/crash/content/app:app_breakpad_mac_to_be_deleted - 'target_name': 'crash_component_breakpad_mac_to_be_deleted', + 'target_name': 'crash_component_breakpad_to_be_deleted', 'variables': { 'conditions': [ - ['OS != "mac" ', { - # There are no source files on any platform but Mac OS X. + ['OS != "mac" and OS != "win"', { + # There are no source files on any platform but Mac OS X and + # Windows. 'crash_component_target_type%': 'none', }, { 'crash_component_target_type%': 'static_library', @@ -239,9 +242,11 @@ 'sources': [ 'crash/content/app/breakpad_mac.h', 'crash/content/app/breakpad_mac.mm', + 'crash/content/app/breakpad_win.cc', + 'crash/content/app/breakpad_win.h', ], 'dependencies': [ - 'crash_component_non_mac', + 'crash_component_non_mac_win', 'crash_component_lib', ], 'defines': ['CRASH_IMPLEMENTATION'], @@ -255,6 +260,15 @@ '../breakpad/src', ], }], + ['OS=="win"', { + 'dependencies': [ + '../breakpad/breakpad.gyp:breakpad_handler', + ], + 'include_dirs': [ + '..', + '../breakpad/src', + ], + }], ], }, { diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn index cc610d6..5bd0494 100644 --- a/components/crash/content/app/BUILD.gn +++ b/components/crash/content/app/BUILD.gn @@ -28,24 +28,27 @@ source_set("lib") { # GYP version: components/crash.gypi:crash_component source_set("app") { sources = [ - "crashpad_mac.h", + "crashpad.h", "crashpad_mac.mm", + "crashpad_win.cc", ] + if (is_mac || is_win) { + sources += [ "crashpad.cc" ] + } + defines = [ "CRASH_IMPLEMENTATION" ] public_deps = [ - ":app_non_mac", + ":app_non_mac_win", ] deps = [ "//base", ] - if (is_mac) { - deps += [ - ":lib", - "//third_party/crashpad/crashpad/client", - ] + deps += [ ":lib" ] + if (is_mac || is_win) { + deps += [ "//third_party/crashpad/crashpad/client" ] } } @@ -71,7 +74,7 @@ source_set("app") { # crash_component_breakpad_mac_to_be_deleted for old Breakpad behavior on # all platforms, or preferably, depend on crash_component to get Breakpad # everywhere except for Mac, where you will get Crashpad. -source_set("app_non_mac") { +source_set("app_non_mac_win") { visibility = [ ":*", "//components/crash/content/browser", @@ -79,8 +82,6 @@ source_set("app_non_mac") { sources = [ "breakpad_linux_impl.h", - "breakpad_win.cc", - "breakpad_win.h", "hard_error_handler_win.cc", "hard_error_handler_win.h", ] @@ -132,15 +133,17 @@ source_set("app_non_mac") { # removed shortly and all consumers will be expected to use Crashpad as # the Mac crash-reporting client. See the comment in the # crash_component_non_mac target for more details. -source_set("app_breakpad_mac_to_be_deleted") { +source_set("app_breakpad_mac_win_to_be_deleted") { deps = [ - ":app_non_mac", + ":app_non_mac_win", ] - if (is_mac) { + if (is_mac || is_win) { sources = [ "breakpad_mac.h", "breakpad_mac.mm", + "breakpad_win.cc", + "breakpad_win.h", ] defines = [ "CRASH_IMPLEMENTATION" ] @@ -149,9 +152,18 @@ source_set("app_breakpad_mac_to_be_deleted") { ":lib", "//base", "//base:base_static", - "//breakpad", "//breakpad:client", "//components/crash/core/common", + "//content/public/common:result_codes", + "//sandbox", ] + + if (is_mac) { + deps += [ "//breakpad" ] + } + + if (is_win) { + deps += [ "//breakpad:breakpad_handler" ] + } } } diff --git a/components/crash/content/app/crashpad.cc b/components/crash/content/app/crashpad.cc new file mode 100644 index 0000000..e3b4124 --- /dev/null +++ b/components/crash/content/app/crashpad.cc @@ -0,0 +1,236 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/crash/content/app/crashpad.h" + +#include <string.h> + +#include <algorithm> +#include <map> +#include <vector> + +#include "base/auto_reset.h" +#include "base/command_line.h" +#include "base/debug/crash_logging.h" +#include "base/debug/dump_without_crashing.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/stringprintf.h" +#include "base/strings/sys_string_conversions.h" +#include "build/build_config.h" +#include "components/crash/content/app/crash_reporter_client.h" +#include "third_party/crashpad/crashpad/client/crash_report_database.h" +#include "third_party/crashpad/crashpad/client/crashpad_client.h" +#include "third_party/crashpad/crashpad/client/crashpad_info.h" +#include "third_party/crashpad/crashpad/client/settings.h" +#include "third_party/crashpad/crashpad/client/simple_string_dictionary.h" +#include "third_party/crashpad/crashpad/client/simulate_crash.h" + +#if defined(OS_POSIX) +#include <unistd.h> +#endif // OS_POSIX + +namespace crash_reporter { + +namespace { + +crashpad::SimpleStringDictionary* g_simple_string_dictionary; +crashpad::CrashReportDatabase* g_database; + +void SetCrashKeyValue(const base::StringPiece& key, + const base::StringPiece& value) { + g_simple_string_dictionary->SetKeyValue(key.data(), value.data()); +} + +void ClearCrashKey(const base::StringPiece& key) { + g_simple_string_dictionary->RemoveKey(key.data()); +} + +bool LogMessageHandler(int severity, + const char* file, + int line, + size_t message_start, + const std::string& string) { + // Only handle FATAL. + if (severity != logging::LOG_FATAL) { + return false; + } + + // In case of an out-of-memory condition, this code could be reentered when + // constructing and storing the key. Using a static is not thread-safe, but if + // multiple threads are in the process of a fatal crash at the same time, this + // should work. + static bool guarded = false; + if (guarded) { + return false; + } + base::AutoReset<bool> guard(&guarded, true); + + // Only log last path component. This matches logging.cc. + if (file) { + const char* slash = strrchr(file, '/'); + if (slash) { + file = slash + 1; + } + } + + CHECK_LE(message_start, string.size()); + std::string message = base::StringPrintf("%s:%d: %s", file, line, + string.c_str() + message_start); + SetCrashKeyValue("LOG_FATAL", message); + + // Rather than including the code to force the crash here, allow the caller to + // do it. + return false; +} + +void DumpWithoutCrashing() { + CRASHPAD_SIMULATE_CRASH(); +} + +} // namespace + +void InitializeCrashpad(bool initial_client, const std::string& process_type) { + static bool initialized = false; + DCHECK(!initialized); + initialized = true; + + const bool browser_process = process_type.empty(); + CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); + + if (initial_client) { +#if defined(OS_MACOSX) + // "relauncher" is hard-coded because it's a Chrome --type, but this + // component can't see Chrome's switches. This is only used for argument + // sanitization. + DCHECK(browser_process || process_type == "relauncher"); +#else + DCHECK(browser_process); +#endif // OS_MACOSX + } else { + DCHECK(!browser_process); + } + + // database_path is only valid in the browser process. + base::FilePath database_path = + internal::PlatformCrashpadInitialization(initial_client, browser_process); + + crashpad::CrashpadInfo* crashpad_info = + crashpad::CrashpadInfo::GetCrashpadInfo(); + +#if defined(OS_MACOSX) +#if defined(NDEBUG) + const bool is_debug_build = false; +#else + const bool is_debug_build = true; +#endif + + // Disable forwarding to the system's crash reporter in processes other than + // the browser process. For the browser, the system's crash reporter presents + // the crash UI to the user, so it's desirable there. Additionally, having + // crash reports appear in ~/Library/Logs/DiagnosticReports provides a + // fallback. Forwarding is turned off for debug-mode builds even for the + // browser process, because the system's crash reporter can take a very long + // time to chew on symbols. + if (!browser_process || is_debug_build) { + crashpad_info->set_system_crash_reporter_forwarding( + crashpad::TriState::kDisabled); + } +#endif // OS_MACOSX + + g_simple_string_dictionary = new crashpad::SimpleStringDictionary(); + crashpad_info->set_simple_annotations(g_simple_string_dictionary); + + base::debug::SetCrashKeyReportingFunctions(SetCrashKeyValue, ClearCrashKey); + crash_reporter_client->RegisterCrashKeys(); + + SetCrashKeyValue("ptype", browser_process ? base::StringPiece("browser") + : base::StringPiece(process_type)); +#if defined(OS_POSIX) + SetCrashKeyValue("pid", base::IntToString(getpid())); +#elif defined(OS_WIN) + SetCrashKeyValue("pid", base::IntToString(::GetCurrentProcessId())); +#endif + + logging::SetLogMessageHandler(LogMessageHandler); + + // If clients called CRASHPAD_SIMULATE_CRASH() instead of + // base::debug::DumpWithoutCrashing(), these dumps would appear as crashes in + // the correct function, at the correct file and line. This would be + // preferable to having all occurrences show up in DumpWithoutCrashing() at + // the same file and line. + base::debug::SetDumpWithoutCrashingFunction(DumpWithoutCrashing); + + if (browser_process) { + g_database = + crashpad::CrashReportDatabase::Initialize(database_path).release(); + + bool enable_uploads = false; + if (!crash_reporter_client->ReportingIsEnforcedByPolicy(&enable_uploads)) { + // Breakpad provided a --disable-breakpad switch to disable crash dumping + // (not just uploading) here. Crashpad doesn't need it: dumping is enabled + // unconditionally and uploading is gated on consent, which tests/bots + // shouldn't have. As a precaution, uploading is also disabled on bots + // even if consent is present. + enable_uploads = crash_reporter_client->GetCollectStatsConsent() && + !crash_reporter_client->IsRunningUnattended(); + } + + SetUploadsEnabled(enable_uploads); + } +} + +void SetUploadsEnabled(bool enable_uploads) { + if (g_database) { + crashpad::Settings* settings = g_database->GetSettings(); + settings->SetUploadsEnabled(enable_uploads); + } +} + +bool GetUploadsEnabled() { + if (g_database) { + crashpad::Settings* settings = g_database->GetSettings(); + bool enable_uploads; + if (settings->GetUploadsEnabled(&enable_uploads)) { + return enable_uploads; + } + } + + return false; +} + +void GetUploadedReports(std::vector<UploadedReport>* uploaded_reports) { + uploaded_reports->clear(); + + if (!g_database) { + return; + } + + std::vector<crashpad::CrashReportDatabase::Report> completed_reports; + crashpad::CrashReportDatabase::OperationStatus status = + g_database->GetCompletedReports(&completed_reports); + if (status != crashpad::CrashReportDatabase::kNoError) { + return; + } + + for (const crashpad::CrashReportDatabase::Report& completed_report : + completed_reports) { + if (completed_report.uploaded) { + UploadedReport uploaded_report; + uploaded_report.local_id = completed_report.uuid.ToString(); + uploaded_report.remote_id = completed_report.id; + uploaded_report.creation_time = completed_report.creation_time; + + uploaded_reports->push_back(uploaded_report); + } + } + + std::sort(uploaded_reports->begin(), uploaded_reports->end(), + [](const UploadedReport& a, const UploadedReport& b) { + return a.creation_time >= b.creation_time; + }); +} + +} // namespace crash_reporter diff --git a/components/crash/content/app/crashpad_mac.h b/components/crash/content/app/crashpad.h index 3e84ca6..6121efb 100644 --- a/components/crash/content/app/crashpad_mac.h +++ b/components/crash/content/app/crashpad.h @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_CRASH_CONTENT_APP_CRASHPAD_MAC_H_ -#define COMPONENTS_CRASH_CONTENT_APP_CRASHPAD_MAC_H_ +#ifndef COMPONENTS_CRASH_CONTENT_APP_CRASHPAD_H_ +#define COMPONENTS_CRASH_CONTENT_APP_CRASHPAD_H_ #include <time.h> #include <string> #include <vector> +#include "base/files/file_path.h" + namespace crash_reporter { // Initializes Crashpad in a way that is appropriate for initial_client and @@ -28,14 +30,14 @@ namespace crash_reporter { // release mode only). Note that when process_type is empty, initial_client must // be true. // -// process_type may be non-empty with initial_client set to true. This indicates -// that an exception handler has been inherited but should be discarded in favor -// of a new Crashpad handler. This configuration should be used infrequently. It -// is provided to allow an install-from-.dmg relauncher process to disassociate -// from an old Crashpad handler so that after performing an installation from a -// disk image, the relauncher process may unmount the disk image that contains -// its inherited crashpad_handler. This is only supported when initial_client is -// true and process_type is "relauncher". +// On Mac, process_type may be non-empty with initial_client set to true. This +// indicates that an exception handler has been inherited but should be +// discarded in favor of a new Crashpad handler. This configuration should be +// used infrequently. It is provided to allow an install-from-.dmg relauncher +// process to disassociate from an old Crashpad handler so that after performing +// an installation from a disk image, the relauncher process may unmount the +// disk image that contains its inherited crashpad_handler. This is only +// supported when initial_client is true and process_type is "relauncher". void InitializeCrashpad(bool initial_client, const std::string& process_type); // Enables or disables crash report upload. This is a property of the Crashpad @@ -68,6 +70,15 @@ struct UploadedReport { // disabled. void GetUploadedReports(std::vector<UploadedReport>* uploaded_reports); +namespace internal { + +// The platform-specific portion of InitializeCrashpad(). +// Returns the database path, if initializing in the browser process. +base::FilePath PlatformCrashpadInitialization(bool initial_client, + bool browser_process); + +} // namespace internal + } // namespace crash_reporter -#endif // COMPONENTS_CRASH_CONTENT_APP_CRASHPAD_MAC_H_ +#endif // COMPONENTS_CRASH_CONTENT_APP_CRASHPAD_H_ diff --git a/components/crash/content/app/crashpad_mac.mm b/components/crash/content/app/crashpad_mac.mm index f87fc96e..5ed4c4e 100644 --- a/components/crash/content/app/crashpad_mac.mm +++ b/components/crash/content/app/crashpad_mac.mm @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/crash/content/app/crashpad_mac.h" +#include "components/crash/content/app/crashpad.h" #include <string.h> #include <unistd.h> @@ -11,9 +11,6 @@ #include <map> #include <vector> -#include "base/auto_reset.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" #include "base/files/file_path.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" @@ -31,81 +28,10 @@ #include "third_party/crashpad/crashpad/client/simulate_crash.h" namespace crash_reporter { +namespace internal { -namespace { - -crashpad::SimpleStringDictionary* g_simple_string_dictionary; -crashpad::CrashReportDatabase* g_database; - -void SetCrashKeyValue(const base::StringPiece& key, - const base::StringPiece& value) { - g_simple_string_dictionary->SetKeyValue(key.data(), value.data()); -} - -void ClearCrashKey(const base::StringPiece& key) { - g_simple_string_dictionary->RemoveKey(key.data()); -} - -bool LogMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& string) { - // Only handle FATAL. - if (severity != logging::LOG_FATAL) { - return false; - } - - // In case of an out-of-memory condition, this code could be reentered when - // constructing and storing the key. Using a static is not thread-safe, but if - // multiple threads are in the process of a fatal crash at the same time, this - // should work. - static bool guarded = false; - if (guarded) { - return false; - } - base::AutoReset<bool> guard(&guarded, true); - - // Only log last path component. This matches logging.cc. - if (file) { - const char* slash = strrchr(file, '/'); - if (slash) { - file = slash + 1; - } - } - - std::string message = base::StringPrintf("%s:%d: %s", file, line, - string.c_str() + message_start); - SetCrashKeyValue("LOG_FATAL", message); - - // Rather than including the code to force the crash here, allow the caller to - // do it. - return false; -} - -void DumpWithoutCrashing() { - CRASHPAD_SIMULATE_CRASH(); -} - -} // namespace - -void InitializeCrashpad(bool initial_client, const std::string& process_type) { - static bool initialized = false; - DCHECK(!initialized); - initialized = true; - - const bool browser_process = process_type.empty(); - CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); - - if (initial_client) { - // "relauncher" is hard-coded because it's a Chrome --type, but this - // component can't see Chrome's switches. This is only used for argument - // sanitization. - DCHECK(browser_process || process_type == "relauncher"); - } else { - DCHECK(!browser_process); - } - +base::FilePath PlatformCrashpadInitialization(bool initial_client, + bool browser_process) { base::FilePath database_path; // Only valid in the browser process. if (initial_client) { @@ -115,6 +41,7 @@ void InitializeCrashpad(bool initial_client, const std::string& process_type) { framework_bundle_path.Append("Helpers").Append("crashpad_handler"); // Is there a way to recover if this fails? + CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); crash_reporter_client->GetCrashDumpLocation(&database_path); // TODO(mark): Reading the Breakpad keys is temporary and transitional. At @@ -168,116 +95,8 @@ void InitializeCrashpad(bool initial_client, const std::string& process_type) { } // @autoreleasepool } - crashpad::CrashpadInfo* crashpad_info = - crashpad::CrashpadInfo::GetCrashpadInfo(); - -#if defined(NDEBUG) - const bool is_debug_build = false; -#else - const bool is_debug_build = true; -#endif - - // Disable forwarding to the system's crash reporter in processes other than - // the browser process. For the browser, the system's crash reporter presents - // the crash UI to the user, so it's desirable there. Additionally, having - // crash reports appear in ~/Library/Logs/DiagnosticReports provides a - // fallback. Forwarding is turned off for debug-mode builds even for the - // browser process, because the system's crash reporter can take a very long - // time to chew on symbols. - if (!browser_process || is_debug_build) { - crashpad_info->set_system_crash_reporter_forwarding( - crashpad::TriState::kDisabled); - } - - g_simple_string_dictionary = new crashpad::SimpleStringDictionary(); - crashpad_info->set_simple_annotations(g_simple_string_dictionary); - - base::debug::SetCrashKeyReportingFunctions(SetCrashKeyValue, ClearCrashKey); - crash_reporter_client->RegisterCrashKeys(); - - SetCrashKeyValue("ptype", browser_process ? base::StringPiece("browser") - : base::StringPiece(process_type)); - SetCrashKeyValue("pid", base::IntToString(getpid())); - - logging::SetLogMessageHandler(LogMessageHandler); - - // If clients called CRASHPAD_SIMULATE_CRASH() instead of - // base::debug::DumpWithoutCrashing(), these dumps would appear as crashes in - // the correct function, at the correct file and line. This would be - // preferable to having all occurrences show up in DumpWithoutCrashing() at - // the same file and line. - base::debug::SetDumpWithoutCrashingFunction(DumpWithoutCrashing); - - if (browser_process) { - g_database = - crashpad::CrashReportDatabase::Initialize(database_path).release(); - - bool enable_uploads = false; - if (!crash_reporter_client->ReportingIsEnforcedByPolicy(&enable_uploads)) { - // Breakpad provided a --disable-breakpad switch to disable crash dumping - // (not just uploading) here. Crashpad doesn't need it: dumping is enabled - // unconditionally and uploading is gated on consent, which tests/bots - // shouldn't have. As a precaution, uploading is also disabled on bots - // even if consent is present. - enable_uploads = crash_reporter_client->GetCollectStatsConsent() && - !crash_reporter_client->IsRunningUnattended(); - } - - SetUploadsEnabled(enable_uploads); - } -} - -void SetUploadsEnabled(bool enable_uploads) { - if (g_database) { - crashpad::Settings* settings = g_database->GetSettings(); - settings->SetUploadsEnabled(enable_uploads); - } -} - -bool GetUploadsEnabled() { - if (g_database) { - crashpad::Settings* settings = g_database->GetSettings(); - bool enable_uploads; - if (settings->GetUploadsEnabled(&enable_uploads)) { - return enable_uploads; - } - } - - return false; -} - -void GetUploadedReports(std::vector<UploadedReport>* uploaded_reports) { - uploaded_reports->clear(); - - if (!g_database) { - return; - } - - std::vector<crashpad::CrashReportDatabase::Report> completed_reports; - crashpad::CrashReportDatabase::OperationStatus status = - g_database->GetCompletedReports(&completed_reports); - if (status != crashpad::CrashReportDatabase::kNoError) { - return; - } - - for (const crashpad::CrashReportDatabase::Report& completed_report : - completed_reports) { - if (completed_report.uploaded) { - UploadedReport uploaded_report; - uploaded_report.local_id = completed_report.uuid.ToString(); - uploaded_report.remote_id = completed_report.id; - uploaded_report.creation_time = completed_report.creation_time; - - uploaded_reports->push_back(uploaded_report); - } - } - - struct { - bool operator()(const UploadedReport& a, const UploadedReport& b) { - return a.creation_time >= b.creation_time; - } - } sort_by_time; - std::sort(uploaded_reports->begin(), uploaded_reports->end(), sort_by_time); + return database_path; } +} // namespace internal } // namespace crash_reporter diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc new file mode 100644 index 0000000..684366e --- /dev/null +++ b/components/crash/content/app/crashpad_win.cc @@ -0,0 +1,202 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/crash/content/app/crashpad.h" + +#include "base/environment.h" +#include "base/lazy_instance.h" +#include "base/memory/scoped_ptr.h" +#include "base/numerics/safe_conversions.h" +#include "base/path_service.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "components/crash/content/app/crash_reporter_client.h" +#include "third_party/crashpad/crashpad/client/crashpad_client.h" +#include "third_party/crashpad/crashpad/client/crashpad_info.h" + +namespace crash_reporter { +namespace internal { + +namespace { + +base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +base::FilePath PlatformCrashpadInitialization(bool initial_client, + bool browser_process) { + base::FilePath database_path; // Only valid in the browser process. + bool result; + + const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME"; + scoped_ptr<base::Environment> env(base::Environment::Create()); + + DCHECK_EQ(initial_client, browser_process); + + if (initial_client) { + CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); + crash_reporter_client->GetCrashDumpLocation(&database_path); + + base::FilePath exe_file; + CHECK(PathService::Get(base::FILE_EXE, &exe_file)); + base::string16 product_name, version, special_build, channel_name; + crash_reporter_client->GetProductNameAndVersion( + exe_file, &product_name, &version, &special_build, &channel_name); + std::map<std::string, std::string> process_annotations; + process_annotations["prod"] = base::UTF16ToUTF8(product_name); + process_annotations["ver"] = base::UTF16ToUTF8(version); + process_annotations["channel"] = base::UTF16ToUTF8(channel_name); + if (!special_build.empty()) + process_annotations["special"] = base::UTF16ToUTF8(special_build); +#if defined(ARCH_CPU_X86) + process_annotations["plat"] = std::string("Win32"); +#elif defined(ARCH_CPU_X86_64) + process_annotations["plat"] = std::string("Win64"); +#endif +#if defined(GOOGLE_CHROME_BUILD) + std::string url = "https://clients2.google.com/cr/report"; +#else + std::string url; +#endif + + std::vector<std::string> arguments; + + // In test binaries, use crashpad_handler directly. Otherwise, we launch + // chrome.exe with --type=crashpad-handler. + if (exe_file.BaseName().value() != FILE_PATH_LITERAL("chrome.exe")) { + base::FilePath exe_dir; + CHECK(PathService::Get(base::DIR_EXE, &exe_dir)); + exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe")); + } else { + arguments.push_back("--type=crashpad-handler"); + } + + result = g_crashpad_client.Get().StartHandler( + exe_file, database_path, url, process_annotations, arguments, false); + + // If we're the browser, push the pipe name into the environment so child + // processes can connect to it. If we inherited another crashpad_handler's + // pipe name, we'll overwrite it here. + env->SetVar(kPipeNameVar, + base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe())); + } else { + std::string pipe_name_utf8; + result = env->GetVar(kPipeNameVar, &pipe_name_utf8); + if (result) { + result = g_crashpad_client.Get().SetHandlerIPCPipe( + base::UTF8ToUTF16(pipe_name_utf8)); + } + } + + if (result) { + result = g_crashpad_client.Get().UseHandler(); + } + + return database_path; +} + +extern "C" { + +// Crashes the process after generating a dump for the provided exception. Note +// that the crash reporter should be initialized before calling this function +// for it to do anything. +// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the +// the name or signature of this function you will break SyzyASAN instrumented +// releases of Chrome. Please contact syzygy-team@chromium.org before doing so! +int __declspec(dllexport) CrashForException( + EXCEPTION_POINTERS* info) { + g_crashpad_client.Get().DumpAndCrash(info); + return EXCEPTION_CONTINUE_SEARCH; +} + +#if defined(ARCH_CPU_X86_64) + +static int CrashForExceptionInNonABICompliantCodeRange( + PEXCEPTION_RECORD ExceptionRecord, + ULONG64 EstablisherFrame, + PCONTEXT ContextRecord, + PDISPATCHER_CONTEXT DispatcherContext) { + EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; + return CrashForException(&info); +} + +// See https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx +typedef struct _UNWIND_INFO { + unsigned char Version : 3; + unsigned char Flags : 5; + unsigned char SizeOfProlog; + unsigned char CountOfCodes; + unsigned char FrameRegister : 4; + unsigned char FrameOffset : 4; + ULONG ExceptionHandler; +} UNWIND_INFO, *PUNWIND_INFO; + +struct ExceptionHandlerRecord { + RUNTIME_FUNCTION runtime_function; + UNWIND_INFO unwind_info; + unsigned char thunk[12]; +}; + +// These are GetProcAddress()d from V8 binding code. +void __declspec(dllexport) __cdecl RegisterNonABICompliantCodeRange( + void* start, + size_t size_in_bytes) { + ExceptionHandlerRecord* record = + reinterpret_cast<ExceptionHandlerRecord*>(start); + + // We assume that the first page of the code range is executable and + // committed and reserved for breakpad. What could possibly go wrong? + + // All addresses are 32bit relative offsets to start. + record->runtime_function.BeginAddress = 0; + record->runtime_function.EndAddress = + base::checked_cast<DWORD>(size_in_bytes); + record->runtime_function.UnwindData = + offsetof(ExceptionHandlerRecord, unwind_info); + + // Create unwind info that only specifies an exception handler. + record->unwind_info.Version = 1; + record->unwind_info.Flags = UNW_FLAG_EHANDLER; + record->unwind_info.SizeOfProlog = 0; + record->unwind_info.CountOfCodes = 0; + record->unwind_info.FrameRegister = 0; + record->unwind_info.FrameOffset = 0; + record->unwind_info.ExceptionHandler = + offsetof(ExceptionHandlerRecord, thunk); + + // Hardcoded thunk. + // mov imm64, rax + record->thunk[0] = 0x48; + record->thunk[1] = 0xb8; + void* handler = &CrashForExceptionInNonABICompliantCodeRange; + memcpy(&record->thunk[2], &handler, 8); + + // jmp rax + record->thunk[10] = 0xff; + record->thunk[11] = 0xe0; + + // Protect reserved page against modifications. + DWORD old_protect; + CHECK(VirtualProtect( + start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect)); + CHECK(RtlAddFunctionTable( + &record->runtime_function, 1, reinterpret_cast<DWORD64>(start))); +} + +void __declspec(dllexport) __cdecl UnregisterNonABICompliantCodeRange( + void* start) { + ExceptionHandlerRecord* record = + reinterpret_cast<ExceptionHandlerRecord*>(start); + + CHECK(RtlDeleteFunctionTable(&record->runtime_function)); +} +#endif // ARCH_CPU_X86_64 + +} // extern "C" + +} // namespace internal +} // namespace crash_reporter diff --git a/components/crash/content/browser/BUILD.gn b/components/crash/content/browser/BUILD.gn index b3a7948..850d622 100644 --- a/components/crash/content/browser/BUILD.gn +++ b/components/crash/content/browser/BUILD.gn @@ -30,7 +30,7 @@ source_set("browser") { ] deps += [ "//breakpad:client", - "//components/crash/content/app:app_non_mac", + "//components/crash/content/app:app_non_mac_win", ] } diff --git a/components/crash/core/common/crash_keys.cc b/components/crash/core/common/crash_keys.cc index c0afc6a..3c3f2fb 100644 --- a/components/crash/core/common/crash_keys.cc +++ b/components/crash/core/common/crash_keys.cc @@ -16,6 +16,14 @@ namespace crash_keys { // Crashpad owns the "guid" key. Chrome's metrics client ID is a separate ID // carried in a distinct "metrics_client_id" field. const char kMetricsClientId[] = "metrics_client_id"; +#elif defined(OS_WIN) +// TODO(scottmg): While transitioning to Crashpad, there are some executables +// that use Crashpad (which use kMetricsClientId), and some that use Breakpad +// (kClientId), and they both use this file. For now we define both, but once +// Breakpad is no longer used on Windows, we will no longer need kClientId, and +// this can be combined with the OS_MACOSX block above. +const char kMetricsClientId[] = "metrics_client_id"; +const char kClientId[] = "guid"; #else const char kClientId[] = "guid"; #endif @@ -44,7 +52,7 @@ void SetMetricsClientIdFromGUID(const std::string& metrics_client_guid) { if (stripped_guid.empty()) return; -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) || defined(OS_WIN) // The crash client ID is maintained by Crashpad and is distinct from the // metrics client ID, which is carried in its own key. base::debug::SetCrashKeyValue(kMetricsClientId, stripped_guid); @@ -56,7 +64,7 @@ void SetMetricsClientIdFromGUID(const std::string& metrics_client_guid) { } void ClearMetricsClientId() { -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) || defined(OS_WIN) // Crashpad always monitors for crashes, but doesn't upload them when // crash reporting is disabled. The preference to upload crash reports is // linked to the preference for metrics reporting. When metrics reporting is diff --git a/components/crash/core/common/crash_keys.h b/components/crash/core/common/crash_keys.h index 70b77ae..6ddb356 100644 --- a/components/crash/core/common/crash_keys.h +++ b/components/crash/core/common/crash_keys.h @@ -48,10 +48,13 @@ const size_t kLargeSize = kSmallSize * 16; // The GUID used to identify this client to the crash system. #if defined(OS_MACOSX) -// On Mac OS X, the crash reporting client ID is the responsibility of Crashpad. -// It is not set directly by Chrome. To make the metrics client ID available on -// the server, it's stored in a distinct key. +// When using Crashpad, the crash reporting client ID is the responsibility of +// Crashpad. It is not set directly by Chrome. To make the metrics client ID +// available on the server, it's stored in a distinct key. extern const char kMetricsClientId[]; +#elif defined(OS_WIN) +extern const char kMetricsClientId[]; +extern const char kClientId[]; #else // When using Breakpad instead of Crashpad, the crash reporting client ID is the // same as the metrics client ID. diff --git a/content/content_shell.gypi b/content/content_shell.gypi index 20a33d9..07769f4 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi @@ -46,7 +46,7 @@ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../cc/blink/cc_blink.gyp:cc_blink', '../cc/cc.gyp:cc', - '../components/components.gyp:crash_component_breakpad_mac_to_be_deleted', + '../components/components.gyp:crash_component_breakpad_to_be_deleted', '../components/components.gyp:devtools_discovery', '../components/components.gyp:devtools_http_handler', '../components/components.gyp:web_cache_renderer', diff --git a/content/ppapi_plugin/ppapi_plugin_main.cc b/content/ppapi_plugin/ppapi_plugin_main.cc index 497e195..52f87a5 100644 --- a/content/ppapi_plugin/ppapi_plugin_main.cc +++ b/content/ppapi_plugin/ppapi_plugin_main.cc @@ -4,6 +4,7 @@ #include "base/base_paths.h" #include "base/command_line.h" +#include "base/debug/crash_logging.h" #include "base/debug/debugger.h" #include "base/files/file_path.h" #include "base/i18n/rtl.h" diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index e721556..9178ec8 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn @@ -195,7 +195,7 @@ static_library("content_shell_lib") { "//base/allocator", "//base/third_party/dynamic_annotations", "//cc", - "//components/crash/content/app:app_breakpad_mac_to_be_deleted", + "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted", "//components/devtools_discovery", "//components/devtools_http_handler", "//components/plugins/renderer", diff --git a/tools/telemetry/telemetry/internal/browser/tab_unittest.py b/tools/telemetry/telemetry/internal/browser/tab_unittest.py index 097df9b..540189c 100644 --- a/tools/telemetry/telemetry/internal/browser/tab_unittest.py +++ b/tools/telemetry/telemetry/internal/browser/tab_unittest.py @@ -64,7 +64,7 @@ class TabTest(tab_test_case.TabTestCase): def testRendererCrash(self): self.assertRaises(exceptions.DevtoolsTargetCrashException, lambda: self._tab.Navigate('chrome://crash', - timeout=5)) + timeout=30)) @decorators.Enabled('has tabs') def testActivateTab(self): |