Skip to content

Commit

Permalink
headless,linux: migrate from breakpad to crashpad
Browse files Browse the repository at this point in the history
When enabled, Breakpad would produce dumps but only upload them for
official builds if no CHROME_HEADLESS environment variable existed.

Crashpad maintains this behavior by overriding
HeadlessCrashReporterClient::IsRunningUnattended(), and
GetCollectStatsConsent(). GetCollectStatsConsent() is implied true by
--enable-crash-reporter passed to headless_shell, or --headless passed
to chrome. Crashpad will internally also only enable upload for
official, google-branded builds.

Removes use of kDisableBreakpad which previously would disable
Breakpad/Linux or Crashpad/Mac, but not Crashpad/Windows. It is
duplicative of --disable-crash-reporter. This patch also causes
--disable-crash-reporter to function for mac, but still not windows.

Bug: 1176772
Change-Id: I651ae30e3c90ec90652743b92c55c63c84b53fbc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2893222
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Cr-Commit-Position: refs/heads/main@{#951799}
  • Loading branch information
Joshua Peraza authored and Chromium LUCI CQ committed Dec 15, 2021
1 parent 6b7765d commit 3f64b4d
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 167 deletions.
1 change: 0 additions & 1 deletion build/check_gn_headers_whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ gpu/command_buffer/service/memory_tracking.h
gpu/config/gpu_lists_version.h
gpu/gles2_conform_support/gtf/gtf_stubs.h
gpu/gpu_export.h
headless/lib/headless_macros.h
ipc/ipc_channel_proxy_unittest_messages.h
ipc/ipc_message_null_macros.h
media/audio/audio_logging.h
Expand Down
13 changes: 9 additions & 4 deletions headless/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,10 @@ component("headless_non_renderer") {
}
}

if (is_linux || is_chromeos) {
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
}

# Normally set to false (see build/args/headless.gn), but we can optionally
# use external v8 startup data too.
if ((!is_win || is_component_build) && v8_use_external_startup_data) {
Expand Down Expand Up @@ -811,10 +815,11 @@ test("headless_browsertests") {
]

if (is_mac) {
deps += [
"//services/device/public/cpp:test_support",
"//third_party/crashpad/crashpad/client",
]
deps += [ "//services/device/public/cpp:test_support" ]
}

if (!is_fuchsia) {
deps += [ "//third_party/crashpad/crashpad/client" ]
}

if (enable_basic_printing) {
Expand Down
90 changes: 21 additions & 69 deletions headless/lib/browser/headless_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#include "headless/lib/browser/headless_browser_main_parts.h"
#include "headless/lib/browser/headless_devtools_manager_delegate.h"
#include "headless/lib/browser/headless_quota_permission_context.h"
#include "headless/lib/headless_macros.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
Expand All @@ -48,12 +47,11 @@
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/switches.h"

#if defined(HEADLESS_USE_BREAKPAD)
#include "base/debug/leak_annotations.h"
#include "components/crash/content/browser/crash_handler_host_linux.h"
#include "components/crash/core/app/breakpad_linux.h"
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "components/crash/core/app/crash_switches.h"
#include "components/crash/core/app/crashpad.h"
#include "content/public/common/content_descriptors.h"
#endif // defined(HEADLESS_USE_BREAKPAD)
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)

#if defined(HEADLESS_USE_POLICY)
#include "components/policy/content/policy_blocklist_navigation_throttle.h"
Expand All @@ -68,67 +66,18 @@

namespace headless {

#if defined(OS_LINUX) || defined(OS_CHROMEOS)
namespace {

#if defined(HEADLESS_USE_BREAKPAD)
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
const std::string& process_type,
const HeadlessBrowser::Options& options) {
base::FilePath dumps_path = options.crash_dumps_dir;
if (dumps_path.empty()) {
bool ok = base::PathService::Get(base::DIR_MODULE, &dumps_path);
DCHECK(ok);
}

{
ANNOTATE_SCOPED_MEMORY_LEAK;
#if defined(OFFICIAL_BUILD)
// Upload crash dumps in official builds, unless we're running in unattended
// mode (not to be confused with headless mode in general -- see
// chrome/common/env_vars.cc).
static const char kHeadless[] = "CHROME_HEADLESS";
bool upload = (getenv(kHeadless) == nullptr);
#else
bool upload = false;
#endif
breakpad::CrashHandlerHostLinux* crash_handler =
new breakpad::CrashHandlerHostLinux(process_type, dumps_path, upload);
crash_handler->StartUploaderThread();
return crash_handler;
}
}

int GetCrashSignalFD(const base::CommandLine& command_line,
const HeadlessBrowser::Options& options) {
if (!breakpad::IsCrashReporterEnabled())
return -1;

std::string process_type =
command_line.GetSwitchValueASCII(::switches::kProcessType);

if (process_type == ::switches::kRendererProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler =
CreateCrashHandlerHost(process_type, options);
return crash_handler->GetDeathSignalSocket();
}

if (process_type == ::switches::kPpapiPluginProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler =
CreateCrashHandlerHost(process_type, options);
return crash_handler->GetDeathSignalSocket();
}

if (process_type == ::switches::kGpuProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler =
CreateCrashHandlerHost(process_type, options);
return crash_handler->GetDeathSignalSocket();
}

return -1;
int fd;
pid_t pid;
return crash_reporter::GetHandlerSocket(&fd, &pid) ? fd : -1;
}
#endif // defined(HEADLESS_USE_BREAKPAD)

} // namespace
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)

// Implements a stub BadgeService. This implementation does nothing, but is
// required because inbound Mojo messages which do not have a registered
Expand Down Expand Up @@ -230,18 +179,16 @@ HeadlessContentBrowserClient::GetGeneratedCodeCacheSettings(
return content::GeneratedCodeCacheSettings(true, 0, context->GetPath());
}

#if defined(OS_POSIX) && !defined(OS_MAC)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
void HeadlessContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
content::PosixFileDescriptorInfo* mappings) {
#if defined(HEADLESS_USE_BREAKPAD)
int crash_signal_fd = GetCrashSignalFD(command_line, *browser_->options());
if (crash_signal_fd >= 0)
mappings->Share(kCrashDumpSignal, crash_signal_fd);
#endif // defined(HEADLESS_USE_BREAKPAD)
}
#endif // defined(OS_POSIX) && !defined(OS_MAC)
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)

void HeadlessContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
Expand All @@ -257,11 +204,16 @@ void HeadlessContentBrowserClient::AppendExtraCommandLineSwitches(
switches::kUserAgent,
old_command_line.GetSwitchValueNative(switches::kUserAgent));
}
#if defined(HEADLESS_USE_BREAKPAD)
// This flag tells child processes to also turn on crash reporting.
if (breakpad::IsCrashReporterEnabled())
command_line->AppendSwitch(::switches::kEnableCrashReporter);
#endif // defined(HEADLESS_USE_BREAKPAD)

#if defined(OS_LINUX) || defined(OS_CHROMEOS)
int fd;
pid_t pid;
if (crash_reporter::GetHandlerSocket(&fd, &pid)) {
command_line->AppendSwitchASCII(
crash_reporter::switches::kCrashpadHandlerPid,
base::NumberToString(pid));
}
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)

// If we're spawning a renderer, then override the language switch.
std::string process_type =
Expand Down
52 changes: 18 additions & 34 deletions headless/lib/headless_content_main_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_content_browser_client.h"
#include "headless/lib/headless_crash_reporter_client.h"
#include "headless/lib/headless_macros.h"
#include "headless/lib/renderer/headless_content_renderer_client.h"
#include "headless/lib/utility/headless_content_utility_client.h"
#include "sandbox/policy/switches.h"
Expand All @@ -48,13 +47,13 @@
#include "headless/embedded_resource_pak.h"
#endif

#if defined(OS_MAC) || defined(OS_WIN)
#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "components/crash/core/app/crashpad.h"
#endif
#endif // defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)

#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "components/crash/core/app/breakpad_linux.h"
#endif
#include "components/crash/core/app/crash_switches.h"
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)

#if defined(OS_POSIX)
#include <signal.h>
Expand Down Expand Up @@ -311,46 +310,34 @@ void HeadlessContentMainDelegate::InitLogging(

void HeadlessContentMainDelegate::InitCrashReporter(
const base::CommandLine& command_line) {
if (command_line.HasSwitch(::switches::kDisableBreakpad))
if (!options()->enable_crash_reporter)
return;

#if defined(OS_FUCHSIA)
// TODO(crbug.com/1226159): Implement this when crash reporting/Breakpad are
// available in Fuchsia.
// TODO(crbug.com/1226159): Implement this when crash reporting is available
// for Fuchsia.
NOTIMPLEMENTED();
#else
const std::string process_type =
command_line.GetSwitchValueASCII(::switches::kProcessType);
crash_reporter::SetCrashReporterClient(g_headless_crash_client.Pointer());
g_headless_crash_client.Pointer()->set_crash_dumps_dir(
options()->crash_dumps_dir);

crash_reporter::InitializeCrashKeys();
crash_keys::SetSwitchesFromCommandLine(command_line, nullptr);

#if defined(HEADLESS_USE_BREAKPAD)
if (!options()->enable_crash_reporter) {
DCHECK(!breakpad::IsCrashReporterEnabled());
return;
}
#if !defined(OS_WIN)
const std::string process_type =
command_line.GetSwitchValueASCII(::switches::kProcessType);
if (process_type != switches::kZygoteProcess)
breakpad::InitCrashReporter(process_type);
#elif defined(OS_MAC)
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
// Avoid adding this dependency in Windows Chrome non component builds, since
// crashpad is already enabled.
// TODO(dvallet): Ideally we would also want to avoid this for component builds.
#elif defined(OS_WIN)
// InitializeCrashpad is already called from main() on Windows, no need to
// call it from here.
#endif // defined(HEADLESS_USE_BREAKPAD)
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
#endif // !defined(OS_WIN)
#endif // defined(OS_FUCHSIA)

// Mark any bug reports from headless mode as such.
static crash_reporter::CrashKeyString<32> headless_key(kHeadlessCrashKey);
headless_key.Set("true");
}


void HeadlessContentMainDelegate::PreSandboxStartup() {
const base::CommandLine& command_line(
*base::CommandLine::ForCurrentProcess());
Expand Down Expand Up @@ -426,14 +413,11 @@ void HeadlessContentMainDelegate::ZygoteForked() {
}
const base::CommandLine& command_line(
*base::CommandLine::ForCurrentProcess());
const std::string process_type =
command_line.GetSwitchValueASCII(::switches::kProcessType);
// Unconditionally try to turn on crash reporting since we do not have access
// to the latest browser options at this point when testing. Breakpad will
// bail out gracefully if the browser process hasn't enabled crash reporting.
#if defined(HEADLESS_USE_BREAKPAD)
breakpad::InitCrashReporter(process_type);
#endif
if (command_line.HasSwitch(crash_reporter::switches::kCrashpadHandlerPid)) {
const std::string process_type =
command_line.GetSwitchValueASCII(::switches::kProcessType);
crash_reporter::InitializeCrashpad(false, process_type);
}
}
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)

Expand Down
35 changes: 18 additions & 17 deletions headless/lib/headless_crash_reporter_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <utility>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
Expand All @@ -30,13 +31,6 @@ HeadlessCrashReporterClient::HeadlessCrashReporterClient() = default;
HeadlessCrashReporterClient::~HeadlessCrashReporterClient() = default;

#if defined(OS_POSIX) && !defined(OS_MAC)
void HeadlessCrashReporterClient::GetProductNameAndVersion(
const char** product_name,
const char** version) {
*product_name = kChromeHeadlessProductName;
*version = PRODUCT_VERSION;
}

void HeadlessCrashReporterClient::GetProductNameAndVersion(
std::string* product_name,
std::string* version,
Expand All @@ -45,10 +39,6 @@ void HeadlessCrashReporterClient::GetProductNameAndVersion(
*version = PRODUCT_VERSION;
*channel = "";
}

base::FilePath HeadlessCrashReporterClient::GetReporterLogFilename() {
return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
}
#endif // defined(OS_POSIX) && !defined(OS_MAC)

bool HeadlessCrashReporterClient::GetCrashDumpLocation(
Expand All @@ -64,6 +54,9 @@ bool HeadlessCrashReporterClient::GetCrashDumpLocation(
!base::PathService::Get(base::DIR_MODULE, &crash_directory)) {
return false;
}
if (crash_dumps_dir_.empty()) {
crash_directory = crash_directory.Append(FILE_PATH_LITERAL("Crashpad"));
}
#if defined(OS_WIN)
*crash_dir = crash_directory.value();
#else
Expand All @@ -72,12 +65,20 @@ bool HeadlessCrashReporterClient::GetCrashDumpLocation(
return true;
}

bool HeadlessCrashReporterClient::EnableBreakpadForProcess(
const std::string& process_type) {
return process_type == ::switches::kRendererProcess ||
process_type == ::switches::kPpapiPluginProcess ||
process_type == ::switches::kZygoteProcess ||
process_type == ::switches::kGpuProcess;
bool HeadlessCrashReporterClient::IsRunningUnattended() {
// CHROME_HEADLESS is not equivalent to running in headless mode. This
// environment variable is set in non-production environments which might be
// running with crash-dumping enabled. It is used to disable certain dialogs
// and in this particular usage disables crash report upload, while leaving
// dumping enabled.
std::unique_ptr<base::Environment> env(base::Environment::Create());
return env->HasVar("CHROME_HEADLESS");
}

bool HeadlessCrashReporterClient::GetCollectStatsConsent() {
// Headless has no way to configure this setting so consent is implied by
// the crash reporter being enabled.
return true;
}

} // namespace content
11 changes: 3 additions & 8 deletions headless/lib/headless_crash_reporter_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,9 @@ class HeadlessCrashReporterClient : public crash_reporter::CrashReporterClient {
const base::FilePath& crash_dumps_dir() const { return crash_dumps_dir_; }

#if defined(OS_POSIX) && !defined(OS_MAC)
// Returns a textual description of the product type and version to include
// in the crash report.
void GetProductNameAndVersion(const char** product_name,
const char** version) override;

void GetProductNameAndVersion(std::string* product_name,
std::string* version,
std::string* channel) override;

base::FilePath GetReporterLogFilename() override;
#endif // defined(OS_POSIX) && !defined(OS_MAC)

#if defined(OS_WIN)
Expand All @@ -47,7 +40,9 @@ class HeadlessCrashReporterClient : public crash_reporter::CrashReporterClient {
bool GetCrashDumpLocation(base::FilePath* crash_dir) override;
#endif

bool EnableBreakpadForProcess(const std::string& process_type) override;
bool IsRunningUnattended() override;

bool GetCollectStatsConsent() override;

private:
base::FilePath crash_dumps_dir_;
Expand Down
14 changes: 0 additions & 14 deletions headless/lib/headless_macros.h

This file was deleted.

Loading

0 comments on commit 3f64b4d

Please sign in to comment.