Commit e13fa8e4 authored by Xi Cheng's avatar Xi Cheng Committed by Commit Bot

[notification_helper.exe] Add crash reporting support

This CL enables crash reporting for notification_helper.exe by reusing the
crashpad handler embedded in chrome.exe. A new crash reporter client is
implemented for the notification_helper process as in class
NotificationHelperCrashReporterClient.

Bug: 734095, 817974
Change-Id: I279e1d7c8e1741fd09af9db9d4915d69b92e56c9
Reviewed-on: https://chromium-review.googlesource.com/924981Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Reviewed-by: default avatarJianzhou Feng <jzfeng@chromium.org>
Commit-Queue: Xi Cheng <chengx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541283}
parent 84b690fe
......@@ -18,6 +18,7 @@
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
#include "base/files/file_path.h"
#include "base/format_macros.h"
#include "base/rand_util.h"
#include "chrome/common/chrome_result_codes.h"
......@@ -54,10 +55,10 @@ void ChromeCrashReporterClient::InitializeCrashReportingForProcess() {
crash_reporter::InitializeCrashpadWithEmbeddedHandler(
process_type.empty(), install_static::UTF16ToUTF8(process_type),
install_static::UTF16ToUTF8(user_data_dir));
install_static::UTF16ToUTF8(user_data_dir), base::FilePath());
}
}
#endif // NACL_WIN64
#endif // !defined(NACL_WIN64)
bool ChromeCrashReporterClient::GetAlternativeCrashDumpLocation(
base::string16* crash_dir) {
......
......@@ -15,7 +15,7 @@ class ChromeCrashReporterClient : public crash_reporter::CrashReporterClient {
// class and initializes crash reporting for the process. The instance is
// leaked.
static void InitializeCrashReportingForProcess();
#endif
#endif // !defined(NACL_WIN64)
ChromeCrashReporterClient();
~ChromeCrashReporterClient() override;
......
......@@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
......@@ -83,8 +84,8 @@ void ConfigureCrashReporting(const InstallerState& installer_state) {
}
}
crash_reporter::InitializeCrashpadWithEmbeddedHandler(true,
"Chrome Installer", "");
crash_reporter::InitializeCrashpadWithEmbeddedHandler(
true, "Chrome Installer", "", base::FilePath());
// Set up the metrics client id (a la child_process_logging::Init()).
std::unique_ptr<metrics::ClientInfo> client_info =
......
......@@ -99,6 +99,7 @@ void InitializeDatabasePath(const base::FilePath& database_path) {
void InitializeCrashpadImpl(bool initial_client,
const std::string& process_type,
const std::string& user_data_dir,
const base::FilePath& exe_path,
bool embedded_handler) {
static bool initialized = false;
DCHECK(!initialized);
......@@ -116,7 +117,8 @@ void InitializeCrashpadImpl(bool initial_client,
#elif defined(OS_WIN)
// "Chrome Installer" is the name historically used for installer binaries
// as processed by the backend.
DCHECK(browser_process || process_type == "Chrome Installer");
DCHECK(browser_process || process_type == "Chrome Installer" ||
process_type == "notification-helper");
#else
#error Port.
#endif // OS_MACOSX
......@@ -126,7 +128,8 @@ void InitializeCrashpadImpl(bool initial_client,
// database_path is only valid in the browser process.
base::FilePath database_path = internal::PlatformCrashpadInitialization(
initial_client, browser_process, embedded_handler, user_data_dir);
initial_client, browser_process, embedded_handler, user_data_dir,
exe_path);
#if defined(OS_MACOSX)
#if defined(NDEBUG)
......@@ -193,14 +196,17 @@ void InitializeCrashpadImpl(bool initial_client,
} // namespace
void InitializeCrashpad(bool initial_client, const std::string& process_type) {
InitializeCrashpadImpl(initial_client, process_type, std::string(), false);
InitializeCrashpadImpl(initial_client, process_type, std::string(),
base::FilePath(), false);
}
#if defined(OS_WIN)
void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
const std::string& process_type,
const std::string& user_data_dir) {
InitializeCrashpadImpl(initial_client, process_type, user_data_dir, true);
const std::string& user_data_dir,
const base::FilePath& exe_path) {
InitializeCrashpadImpl(initial_client, process_type, user_data_dir, exe_path,
true);
}
#endif // OS_WIN
......
......@@ -53,20 +53,21 @@ namespace crash_reporter {
// supported when initial_client is true and process_type is "relauncher".
//
// On Windows, use InitializeCrashpadWithEmbeddedHandler() when crashpad_handler
// is embedded into this binary and can be started by launching the current
// process with --type=crashpad-handler. Otherwise, this function should be used
// and will launch an external crashpad_handler.exe which is generally used for
// test situations.
// is embedded into a binary that can be launched with --type=crashpad-handler.
// Otherwise, this function should be used and will launch an external
// crashpad_handler.exe which is generally used for test situations.
void InitializeCrashpad(bool initial_client, const std::string& process_type);
#if defined(OS_WIN)
// This is the same as InitializeCrashpad(), but rather than launching a
// crashpad_handler executable, relaunches the current executable with a command
// line argument of --type=crashpad-handler. If user_data_dir is non-empty, it
// is added to the handler's command line for use by Chrome Crashpad extensions.
// crashpad_handler executable, relaunches the executable at |exe_path| or the
// current executable if |exe_path| is empty with a command line argument of
// --type=crashpad-handler. If |user_data_dir| is non-empty, it is added to the
// handler's command line for use by Chrome Crashpad extensions.
void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
const std::string& process_type,
const std::string& user_data_dir);
const std::string& user_data_dir,
const base::FilePath& exe_path);
#endif // OS_WIN
// Returns the CrashpadClient for this process. This will lazily create it if
......@@ -146,14 +147,16 @@ void UnregisterNonABICompliantCodeRangeImpl(void* start);
#endif // defined(OS_WIN)
// The platform-specific portion of InitializeCrashpad(). On windows, if
// user_data_dir is non-empty, the user data directory will be passed to the
// handler process for use by Chrome Crashpad extensions.
// Returns the database path, if initializing in the browser process.
// The platform-specific portion of InitializeCrashpad(). On Windows, if
// |user_data_dir| is non-empty, the user data directory will be passed to the
// handler process for use by Chrome Crashpad extensions; if |exe_path| is
// non-empty, it specifies the path to the executable holding the embedded
// handler. Returns the database path, if initializing in the browser process.
base::FilePath PlatformCrashpadInitialization(bool initial_client,
bool browser_process,
bool embedded_handler,
const std::string& user_data_dir);
const std::string& user_data_dir,
const base::FilePath& exe_path);
} // namespace internal
......
......@@ -30,14 +30,15 @@
namespace crash_reporter {
namespace internal {
base::FilePath PlatformCrashpadInitialization(
bool initial_client,
bool browser_process,
bool embedded_handler,
const std::string& user_data_dir) {
base::FilePath PlatformCrashpadInitialization(bool initial_client,
bool browser_process,
bool embedded_handler,
const std::string& user_data_dir,
const base::FilePath& exe_path) {
base::FilePath database_path; // Only valid in the browser process.
base::FilePath metrics_path; // Only valid in the browser process.
DCHECK(!embedded_handler); // This is not used on Mac.
DCHECK(exe_path.empty()); // This is not used on Mac.
if (initial_client) {
@autoreleasepool {
......
......@@ -53,11 +53,11 @@ void GetPlatformCrashpadAnnotations(
#endif
}
base::FilePath PlatformCrashpadInitialization(
bool initial_client,
bool browser_process,
bool embedded_handler,
const std::string& user_data_dir) {
base::FilePath PlatformCrashpadInitialization(bool initial_client,
bool browser_process,
bool embedded_handler,
const std::string& user_data_dir,
const base::FilePath& exe_path) {
base::FilePath database_path; // Only valid in the browser process.
base::FilePath metrics_path; // Only valid in the browser process.
......@@ -90,11 +90,14 @@ base::FilePath PlatformCrashpadInitialization(
// isn't present in the environment then the default URL will remain.
env->GetVar(kServerUrlVar, &url);
wchar_t exe_file_path[MAX_PATH] = {};
CHECK(
::GetModuleFileName(nullptr, exe_file_path, arraysize(exe_file_path)));
base::FilePath exe_file(exe_path);
if (exe_file.empty()) {
wchar_t exe_file_path[MAX_PATH] = {};
CHECK(::GetModuleFileName(nullptr, exe_file_path,
arraysize(exe_file_path)));
base::FilePath exe_file(exe_file_path);
exe_file = base::FilePath(exe_file_path);
}
if (crash_reporter_client->GetShouldDumpLargerDumps()) {
const uint32_t kIndirectMemoryLimit = 4 * 1024 * 1024;
......
......@@ -10,6 +10,7 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/path_service.h"
......@@ -209,8 +210,8 @@ void HeadlessContentMainDelegate::InitCrashReporter(
// crashpad is already enabled.
// TODO(dvallet): Ideally we would also want to avoid this for component builds.
#elif defined(OS_WIN) && !defined(CHROME_MULTIPLE_DLL)
crash_reporter::InitializeCrashpadWithEmbeddedHandler(process_type.empty(),
process_type, "");
crash_reporter::InitializeCrashpadWithEmbeddedHandler(
process_type.empty(), process_type, "", base::FilePath());
#endif // defined(HEADLESS_USE_BREAKPAD)
#endif // defined(OS_FUCHSIA)
}
......
......@@ -10,6 +10,8 @@ executable("notification_helper") {
sources = [
"notification_helper.cc",
"notification_helper.rc",
"notification_helper_crash_reporter_client.cc",
"notification_helper_crash_reporter_client.h",
]
configs -= [ "//build/config/win:console" ]
......@@ -20,7 +22,11 @@ executable("notification_helper") {
":version_resources",
"//base",
"//build/win:default_exe_manifest",
"//chrome/common:version_header",
"//chrome/install_static:primary_module",
"//components/crash/content/app",
"//components/crash/content/app:crash_export_thunks",
"//components/version_info:channel",
]
libs = [ "runtimeobject.lib" ]
......@@ -33,6 +39,8 @@ source_set("lib") {
"com_server_module.h",
"notification_activator.cc",
"notification_activator.h",
"notification_helper_util.cc",
"notification_helper_util.h",
"trace_util.cc",
"trace_util.h",
]
......
......@@ -2,7 +2,11 @@ include_rules = [
"+base",
"+chrome/common/chrome_constants.h",
"+chrome/common/chrome_switches.h",
"+chrome/common/chrome_version.h",
"+chrome/install_static",
"+chrome/installer/setup",
"+chrome/installer/util",
"+components/crash/content/app/crashpad.h",
"+components/crash/content/app/crash_reporter_client.h",
"+components/version_info/channel.h",
]
......@@ -7,38 +7,12 @@
#include <shellapi.h>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/win/windows_types.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "notification_helper/notification_helper_util.h"
#include "notification_helper/trace_util.h"
namespace {
// Returns the file path of chrome.exe if found, or an empty file path if not.
base::FilePath GetChromeExePath() {
// Look for chrome.exe one folder above notification_helper.exe (as expected
// in Chrome installs). Failing that, look for it alonside
// notification_helper.exe.
base::FilePath dir_exe;
if (!PathService::Get(base::DIR_EXE, &dir_exe))
return base::FilePath();
base::FilePath chrome_exe =
dir_exe.DirName().Append(chrome::kBrowserProcessExecutableName);
if (!base::PathExists(chrome_exe)) {
chrome_exe = dir_exe.Append(chrome::kBrowserProcessExecutableName);
if (!base::PathExists(chrome_exe))
return base::FilePath();
}
return chrome_exe;
}
} // namespace
namespace notification_helper {
NotificationActivator::~NotificationActivator() = default;
......
......@@ -6,11 +6,14 @@
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/process/memory.h"
#include "base/win/process_startup_helper.h"
#include "base/win/scoped_winrt_initializer.h"
#include "chrome/install_static/product_install_details.h"
#include "notification_helper/com_server_module.h"
#include "notification_helper/notification_helper_crash_reporter_client.h"
#include "notification_helper/notification_helper_util.h"
#include "notification_helper/trace_util.h"
extern "C" int WINAPI wWinMain(HINSTANCE instance,
......@@ -25,6 +28,13 @@ extern "C" int WINAPI wWinMain(HINSTANCE instance,
// Initialize the CommandLine singleton from the environment.
base::CommandLine::Init(0, nullptr);
// Use crashpad embedded in chrome.exe as the crash handler.
base::FilePath chrome_exe_path = notification_helper::GetChromeExePath();
if (!chrome_exe_path.empty()) {
NotificationHelperCrashReporterClient::
InitializeCrashReportingForProcessWithHandler(chrome_exe_path);
}
// Make sure the process exits cleanly on unexpected errors.
base::EnableTerminationOnHeapCorruption();
base::EnableTerminationOnOutOfMemory();
......
// Copyright 2018 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 "notification_helper/notification_helper_crash_reporter_client.h"
#include <memory>
#include "base/debug/leak_annotations.h"
#include "base/file_version_info.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_version.h"
#include "chrome/install_static/install_util.h"
#include "chrome/install_static/user_data_dir.h"
#include "components/crash/content/app/crashpad.h"
#include "components/version_info/channel.h"
NotificationHelperCrashReporterClient::NotificationHelperCrashReporterClient() =
default;
NotificationHelperCrashReporterClient::
~NotificationHelperCrashReporterClient() = default;
// static
void NotificationHelperCrashReporterClient::
InitializeCrashReportingForProcessWithHandler(
const base::FilePath& exe_path) {
DCHECK(!exe_path.empty());
static NotificationHelperCrashReporterClient* instance = nullptr;
if (instance)
return;
instance = new NotificationHelperCrashReporterClient();
ANNOTATE_LEAKING_OBJECT_PTR(instance);
crash_reporter::SetCrashReporterClient(instance);
base::string16 user_data_dir;
install_static::GetUserDataDirectory(&user_data_dir, nullptr);
crash_reporter::InitializeCrashpadWithEmbeddedHandler(
true, "notification-helper", install_static::UTF16ToUTF8(user_data_dir),
exe_path);
}
bool NotificationHelperCrashReporterClient::ShouldCreatePipeName(
const base::string16& process_type) {
return true;
}
bool NotificationHelperCrashReporterClient::GetAlternativeCrashDumpLocation(
base::string16* crash_dir) {
return false;
}
void NotificationHelperCrashReporterClient::GetProductNameAndVersion(
const base::string16& exe_path,
base::string16* product_name,
base::string16* version,
base::string16* special_build,
base::string16* channel_name) {
// Report crashes under the same product name as the browser. This string
// MUST match server-side configuration.
*product_name = base::ASCIIToUTF16(PRODUCT_SHORTNAME_STRING);
std::unique_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(base::FilePath(exe_path)));
if (version_info) {
*version = version_info->product_version();
*special_build = version_info->special_build();
} else {
*version = L"0.0.0.0-devel";
*special_build = L"";
}
*channel_name = install_static::GetChromeChannelName();
}
bool NotificationHelperCrashReporterClient::ShouldShowRestartDialog(
base::string16* title,
base::string16* message,
bool* is_rtl_locale) {
// There is no UX associated with notification_helper, so no dialog should be
// shown.
return false;
}
bool NotificationHelperCrashReporterClient::AboutToRestart() {
// The notification_helper should never be restarted after a crash.
return false;
}
bool NotificationHelperCrashReporterClient::GetDeferredUploadsSupported(
bool is_per_user_install) {
return false;
}
bool NotificationHelperCrashReporterClient::GetIsPerUserInstall() {
return !install_static::IsSystemInstall();
}
bool NotificationHelperCrashReporterClient::GetShouldDumpLargerDumps() {
// Use large dumps for all but the stable channel.
return install_static::GetChromeChannel() != version_info::Channel::STABLE;
}
int NotificationHelperCrashReporterClient::GetResultCodeRespawnFailed() {
// The restart dialog is never shown for the notification_helper.
NOTREACHED();
return 0;
}
bool NotificationHelperCrashReporterClient::GetCrashDumpLocation(
base::string16* crash_dir) {
*crash_dir = install_static::GetCrashDumpLocation();
return !crash_dir->empty();
}
bool NotificationHelperCrashReporterClient::GetCrashMetricsLocation(
base::string16* metrics_dir) {
install_static::GetUserDataDirectory(metrics_dir, nullptr);
return !metrics_dir->empty();
}
bool NotificationHelperCrashReporterClient::IsRunningUnattended() {
return install_static::HasEnvironmentVariable16(install_static::kHeadless);
}
bool NotificationHelperCrashReporterClient::GetCollectStatsConsent() {
return install_static::GetCollectStatsConsent();
}
bool NotificationHelperCrashReporterClient::GetCollectStatsInSample() {
return install_static::GetCollectStatsInSample();
}
bool NotificationHelperCrashReporterClient::ReportingIsEnforcedByPolicy(
bool* enabled) {
return install_static::ReportingIsEnforcedByPolicy(enabled);
}
bool NotificationHelperCrashReporterClient::
ShouldMonitorCrashHandlerExpensively() {
// The expensive mechanism dedicates a process to be crashpad_handler's own
// crashpad_handler.
return false;
}
bool NotificationHelperCrashReporterClient::EnableBreakpadForProcess(
const std::string& process_type) {
// This is not used by Crashpad (at least on Windows).
NOTREACHED();
return true;
}
// Copyright 2018 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 NOTIFICATION_HELPER_NOTIFICATION_HELPER_CRASH_REPORTER_CLIENT_H_
#define NOTIFICATION_HELPER_NOTIFICATION_HELPER_CRASH_REPORTER_CLIENT_H_
#include "base/files/file_path.h"
#include "base/macros.h"
#include "components/crash/content/app/crash_reporter_client.h"
class NotificationHelperCrashReporterClient
: public crash_reporter::CrashReporterClient {
public:
// Instantiates a process wide instance of the
// NotificationHelperCrashReporterClient class and initializes crash reporting
// for the process. The instance is leaked.
// Uses the crashpad handler embedded in the executable at |exe_path|.
static void InitializeCrashReportingForProcessWithHandler(
const base::FilePath& exe_path);
NotificationHelperCrashReporterClient();
~NotificationHelperCrashReporterClient() override;
// crash_reporter::CrashReporterClient:
bool ShouldCreatePipeName(const base::string16& process_type) override;
bool GetAlternativeCrashDumpLocation(base::string16* crash_dir) override;
void GetProductNameAndVersion(const base::string16& exe_path,
base::string16* product_name,
base::string16* version,
base::string16* special_build,
base::string16* channel_name) override;
bool ShouldShowRestartDialog(base::string16* title,
base::string16* message,
bool* is_rtl_locale) override;
bool AboutToRestart() override;
bool GetDeferredUploadsSupported(bool is_per_user_install) override;
bool GetIsPerUserInstall() override;
bool GetShouldDumpLargerDumps() override;
int GetResultCodeRespawnFailed() override;
bool GetCrashDumpLocation(base::string16* crash_dir) override;
bool GetCrashMetricsLocation(base::string16* metrics_dir) override;
bool IsRunningUnattended() override;
bool GetCollectStatsConsent() override;
bool GetCollectStatsInSample() override;
bool ReportingIsEnforcedByPolicy(bool* enabled) override;
bool ShouldMonitorCrashHandlerExpensively() override;
bool EnableBreakpadForProcess(const std::string& process_type) override;
private:
DISALLOW_COPY_AND_ASSIGN(NotificationHelperCrashReporterClient);
};
#endif // NOTIFICATION_HELPER_NOTIFICATION_HELPER_CRASH_REPORTER_CLIENT_H_
// Copyright 2018 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 "notification_helper/notification_helper_util.h"
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "chrome/common/chrome_constants.h"
namespace notification_helper {
base::FilePath GetChromeExePath() {
// Look for chrome.exe one folder above notification_helper.exe (as expected
// in Chrome installs). Failing that, look for it alonside
// notification_helper.exe.
base::FilePath dir_exe;
if (!PathService::Get(base::DIR_EXE, &dir_exe))
return base::FilePath();
base::FilePath chrome_exe =
dir_exe.DirName().Append(chrome::kBrowserProcessExecutableName);
if (!base::PathExists(chrome_exe)) {
chrome_exe = dir_exe.Append(chrome::kBrowserProcessExecutableName);
if (!base::PathExists(chrome_exe))
return base::FilePath();
}
return chrome_exe;
}
} // namespace notification_helper
// Copyright 2018 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 NOTIFICATION_HELPER_NOTIFICATION_HELPER_UTIL_H_
#define NOTIFICATION_HELPER_NOTIFICATION_HELPER_UTIL_H_
#include "base/files/file_path.h"
namespace notification_helper {
// Returns the file path of chrome.exe if found, or an empty file path if not.
base::FilePath GetChromeExePath();
} // namespace notification_helper
#endif // NOTIFICATION_HELPER_NOTIFICATION_HELPER_UTIL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment