Commit e00760c6 authored by Joe Mason's avatar Joe Mason Committed by Commit Bot

Add chrome_cleaner/crash dir

Also add crash and logging deps to test_main.cc

R=proberge

Bug: 830892
Change-Id: I1fae62bfcff0beded07a1827cab1d58dab79f3ac
Reviewed-on: https://chromium-review.googlesource.com/1163635
Commit-Queue: Joe Mason <joenotcharles@chromium.org>
Reviewed-by: default avatarproberge <proberge@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#581388}
parent 9c02c1b0
......@@ -11,11 +11,22 @@ test("chrome_cleaner_unittests") {
]
deps = [
# Dependencies of the test harness.
":other_executable_definitions",
"//base",
"//base/test:test_support",
"//chrome/chrome_cleaner/crash:crashpad_lib",
"//chrome/chrome_cleaner/engines:resources",
"//chrome/chrome_cleaner/logging:common",
"//chrome/chrome_cleaner/os:cleaner_os",
"//chrome/chrome_cleaner/os:common_os",
"//chrome/chrome_cleaner/os:common_os",
"//chrome/chrome_cleaner/pup_data:pup_data_base",
"//chrome/chrome_cleaner/settings:settings_types",
"//chrome/chrome_cleaner/test:test_pup_data",
"//chrome/chrome_cleaner/test:test_util",
"//sandbox/win:sandbox",
"//testing/gtest",
# Tests from sub-directories.
"//chrome/chrome_cleaner/http:unittest_sources",
......@@ -25,15 +36,6 @@ test("chrome_cleaner_unittests") {
"//chrome/chrome_cleaner/settings:unittest_sources",
"//chrome/chrome_cleaner/strings:unittest_sources",
"//chrome/chrome_cleaner/test:unittest_sources",
# Dependencies of the test harness.
"//base",
"//base/test:test_support",
"//chrome/chrome_cleaner/os:cleaner_os",
"//chrome/chrome_cleaner/os:common_os",
"//chrome/chrome_cleaner/test:test_util",
"//sandbox/win:sandbox",
"//testing/gtest",
]
}
......
# 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.
source_set("crash_keys") {
sources = [
"crash_keys.cc",
"crash_keys.h",
]
deps = [
"//base:base",
"//third_party/crashpad/crashpad/client:client",
]
}
source_set("crashpad_lib") {
sources = [
"crash_client.h",
"crash_reporter.h",
"crashpad_crash_client.cc",
"crashpad_crash_client.h",
"crashpad_crash_reporter.cc",
]
deps = [
":crash_keys",
"//base:base",
"//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
"//chrome/chrome_cleaner/constants:common_strings",
"//chrome/chrome_cleaner/logging:common",
"//chrome/chrome_cleaner/os:common_os",
"//chrome/chrome_cleaner/settings:settings",
"//chrome/chrome_cleaner/settings:settings_types",
"//third_party/crashpad/crashpad/client",
"//third_party/crashpad/crashpad/handler",
]
}
include_rules = [
"+third_party/crashpad",
]
// 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 CHROME_CHROME_CLEANER_CRASH_CRASH_CLIENT_H_
#define CHROME_CHROME_CLEANER_CRASH_CRASH_CLIENT_H_
#include <map>
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
#include "chrome/chrome_cleaner/settings/settings_types.h"
namespace chrome_cleaner {
// This class manages interaction with the crash reporter.
class CrashClient {
public:
enum class Mode { REPORTER, CLEANER, MODE_COUNT };
static CrashClient* GetInstance();
// Set |client_id| to the current guid associated with crashes. |client_id|
// may be empty if no guid is associated.
static void GetClientId(base::string16* client_id);
// Returns whether upload of crashes is enabled or not.
static bool IsUploadEnabled();
CrashClient() = default;
virtual ~CrashClient() = default;
// Initializes collection and upload of crash reports. This will only be done
// if the user has agreed to crash dump reporting.
//
// Crash reporting has to be initialized as early as possible (e.g., the first
// thing in main()) to catch crashes occurring during process startup. Crashes
// which occur during the global static construction phase will not be caught
// and reported. This should not be a problem as static non-POD objects are
// not allowed by the style guide and exceptions to this rule are rare.
//
// |mode| controls a custom info entry present in the generated dumps to allow
// distinguishing between cleaner and reporter crashes on the backend.
//
// |process_type| identifies the type of process that reported the crash.
virtual bool InitializeCrashReporting(Mode mode,
SandboxType process_type) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CrashClient);
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_CRASH_CRASH_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 "chrome/chrome_cleaner/crash/crash_keys.h"
#include "base/command_line.h"
#include "base/format_macros.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/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "third_party/crashpad/crashpad/client/crashpad_info.h"
#include "third_party/crashpad/crashpad/client/simple_string_dictionary.h"
namespace chrome_cleaner {
namespace {
base::Lock& GetCrashKeyLock() {
static base::Lock* crash_key_lock = new base::Lock();
return *crash_key_lock;
}
crashpad::SimpleStringDictionary* GetCrashKeys() {
// TODO(crbug.com/870715): Use the new crash key API from
// https://cs.chromium.org/chromium/src/components/crash/core/common/crash_key.h
static crashpad::SimpleStringDictionary* crash_keys =
new crashpad::SimpleStringDictionary();
return crash_keys;
}
void SetCrashKeyInDictionary(crashpad::SimpleStringDictionary* crash_keys,
base::StringPiece key,
base::StringPiece value) {
if (crash_keys->GetValueForKey(key))
LOG(WARNING) << "Crash key \"" << key << "\" being overwritten";
else
DCHECK_LT(crash_keys->GetCount(), crash_keys->num_entries);
crash_keys->SetKeyValue(key, value);
}
} // namespace
void SetCrashKey(base::StringPiece key, base::StringPiece value) {
base::AutoLock lock(GetCrashKeyLock());
SetCrashKeyInDictionary(GetCrashKeys(), key, value);
}
void SetCrashKeysFromCommandLine() {
// Based on Chrome's crash_keys::SetSwitchesFromCommandLine.
static constexpr size_t kMaxArgs = 16;
static constexpr char kKeyFormat[] = "CommandLineArg-%02" PRIuS;
static constexpr char kSizeKey[] = "CommandLineSize";
base::AutoLock lock(GetCrashKeyLock());
crashpad::SimpleStringDictionary* crash_keys = GetCrashKeys();
// Make sure this was only called once.
DCHECK(!crash_keys->GetValueForKey(kSizeKey));
const base::CommandLine::StringVector& argv =
base::CommandLine::ForCurrentProcess()->argv();
// Record the true number of arguments in case there are too many to store.
SetCrashKeyInDictionary(crash_keys, kSizeKey,
base::NumberToString(argv.size()));
// Go through the argv, including the exec path in argv[0]. Stop if there are
// too many arguments to hold in crash keys.
for (size_t key_i = 0; key_i < argv.size() && key_i < kMaxArgs; ++key_i) {
SetCrashKeyInDictionary(crash_keys, base::StringPrintf(kKeyFormat, key_i),
base::WideToUTF8(argv[key_i]));
}
}
void UseCrashKeysToAnnotate(crashpad::CrashpadInfo* crashpad_info) {
crashpad_info->set_simple_annotations(GetCrashKeys());
}
} // namespace chrome_cleaner
// 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 CHROME_CHROME_CLEANER_CRASH_CRASH_KEYS_H_
#define CHROME_CHROME_CLEANER_CRASH_CRASH_KEYS_H_
#include <string>
#include "base/strings/string_piece_forward.h"
namespace crashpad {
// Forward-declare CrashpadInfo instead of including crashpad_info.h because
// the header pulls in extra dependencies that would need to be inherited by
// every file using crash_keys.h.
struct CrashpadInfo;
} // namespace crashpad
namespace chrome_cleaner {
// Sets the crash key |key| to the specified |value|. The key will be
// overwritten if it was already present. This is thread-safe.
void SetCrashKey(base::StringPiece key, base::StringPiece value);
// Records the current process's command-line in a set of crash keys. This is
// thread-safe.
void SetCrashKeysFromCommandLine();
// Sets |crashpad_info| to use this process's crash key dictionary for
// annotations. Note the annotations are not used in a thread-safe way by
// Crashpad, but that should be acceptable because they are only used while
// dumping a crash.
void UseCrashKeysToAnnotate(crashpad::CrashpadInfo* crashpad_info);
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_CRASH_CRASH_KEYS_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.
#ifndef CHROME_CHROME_CLEANER_CRASH_CRASH_REPORTER_H_
#define CHROME_CHROME_CLEANER_CRASH_CRASH_REPORTER_H_
#include <string>
#include "base/strings/string16.h"
// Starts a new instance of this executable running as the crash reporter
// process.
void StartCrashReporter(const std::string version);
// Runs the crash reporter message loop within the current process. On return,
// the current process should exit.
int CrashReporterMain();
// Returns the name of the IPC pipe that is used to communicate with the crash
// reporter process, or an empty string if the current process is not connected
// to a crash reporter process.
base::string16 GetCrashReporterIPCPipeName();
// Uses the crash reporter with the specified |ipc_pipe_name|, instead of
// starting a new crash reporter process.
void UseCrashReporter(const base::string16& ipc_pipe_name);
#endif // CHROME_CHROME_CLEANER_CRASH_CRASH_REPORTER_H_
This diff is collapsed.
// 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 CHROME_CHROME_CLEANER_CRASH_CRASHPAD_CRASH_CLIENT_H_
#define CHROME_CHROME_CLEANER_CRASH_CRASHPAD_CRASH_CLIENT_H_
#include <map>
#include <memory>
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/sequence_checker.h"
#include "base/strings/string16.h"
#include "chrome/chrome_cleaner/crash/crash_client.h"
#include "chrome/chrome_cleaner/settings/settings_types.h"
#include "third_party/crashpad/crashpad/client/crash_report_database.h"
namespace base {
template <typename T>
struct DefaultSingletonTraits;
} // namespace base
namespace chrome_cleaner {
// This class manages interaction with the Crashpad reporter.
class CrashpadCrashClient : public CrashClient {
public:
~CrashpadCrashClient() override;
// Initializes the crash database only. Used in the crash reporter, which
// cannot connect to itself to upload its own crashes.
bool InitializeDatabaseOnly();
crashpad::CrashReportDatabase* database() { return database_.get(); }
// CrashClient:
bool InitializeCrashReporting(Mode mode, SandboxType process_type) override;
static CrashpadCrashClient* GetInstance();
// Sets |client_id| to the current guid associated with crashes. |client_id|
// may be empty if no guid is associated.
static void GetClientId(base::string16* client_id);
// Returns whether upload of crashes is enabled or not.
static bool IsUploadEnabled();
private:
friend class base::Singleton<CrashpadCrashClient>;
friend struct base::DefaultSingletonTraits<CrashpadCrashClient>;
CrashpadCrashClient();
// Removes already uploaded reports and limits the number of reports that
// stay on disk.
void DeleteStaleReports();
SEQUENCE_CHECKER(sequence_checker_);
std::unique_ptr<crashpad::CrashReportDatabase> database_;
DISALLOW_COPY_AND_ASSIGN(CrashpadCrashClient);
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_CRASH_CRASHPAD_CRASH_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 <algorithm>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
#include "chrome/chrome_cleaner/crash/crashpad_crash_client.h"
#include "chrome/chrome_cleaner/logging/scoped_logging.h"
#include "chrome/chrome_cleaner/os/disk_util.h"
#include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
#include "chrome/chrome_cleaner/os/system_util.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
#include "third_party/crashpad/crashpad/handler/handler_main.h"
namespace {
// The URL where crash reports are uploaded.
const char kReportUploadURL[] = "https://clients2.google.com/cr/report";
// Whether the current process is connected to a crash handler process.
bool g_is_connected_to_crash_handler = false;
} // namespace
crashpad::CrashpadClient* GetCrashpadClient() {
static auto* crashpad_client = new crashpad::CrashpadClient();
return crashpad_client;
}
void AppendSwitchIfExisting(const base::CommandLine& command_line,
const std::string& switch_name,
std::vector<std::string>* arguments) {
if (command_line.HasSwitch(switch_name)) {
// String format: --%s=%s
arguments->push_back(
base::StrCat({"--", switch_name, "=",
command_line.GetSwitchValueASCII(switch_name)}));
}
}
void StartCrashReporter(const std::string version) {
static bool started = false;
DCHECK(!started);
started = true;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::FilePath handler_path =
chrome_cleaner::PreFetchedPaths::GetInstance()->GetExecutablePath();
base::FilePath database_path;
if (!chrome_cleaner::GetAppDataProductDirectory(&database_path)) {
LOG(DFATAL) << "Failed to get AppData product directory";
return;
}
std::map<std::string, std::string> annotations; // Crash keys.
annotations["ver"] = version;
annotations["prod"] = "ChromeFoil";
annotations["plat"] = "Win32";
std::vector<std::string> arguments;
arguments.push_back(
base::StrCat({"--", chrome_cleaner::kCrashHandlerSwitch}));
AppendSwitchIfExisting(*command_line, chrome_cleaner::kTestLoggingURLSwitch,
&arguments);
AppendSwitchIfExisting(*command_line, chrome_cleaner::kCleanupIdSwitch,
&arguments);
crashpad::CrashpadClient* client = GetCrashpadClient();
if (!client->StartHandler(handler_path, database_path,
/*metrics_dir=*/base::FilePath(), kReportUploadURL,
annotations, arguments, /*restartable=*/true,
/*asynchronous_start=*/false)) {
LOG(DFATAL) << "Failed to start handler.";
} else {
g_is_connected_to_crash_handler = true;
LOG(INFO) << "Crash handler launched and ready.";
}
}
void RemoveSwitchIfExisting(const char* const switch_to_remove,
std::vector<base::string16>* argv) {
const base::string16 pattern =
base::StrCat({L"--", base::UTF8ToWide(switch_to_remove)});
auto matches_switch = [&pattern](const base::string16& argument) -> bool {
return base::StartsWith(argument, pattern, base::CompareCase::SENSITIVE);
};
argv->erase(std::remove_if(argv->begin(), argv->end(), matches_switch),
argv->end());
}
int CrashReporterMain() {
chrome_cleaner::ScopedLogging scoped_logging(L"-crashpad");
// Make sure not to take too much of the machines's resources.
chrome_cleaner::SetBackgroundMode();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// This function should only run if --crash-handler switch is present.
DCHECK(command_line->HasSwitch(chrome_cleaner::kCrashHandlerSwitch));
std::vector<base::string16> argv = command_line->argv();
// Because of https://bugs.chromium.org/p/crashpad/issues/detail?id=82,
// Crashpad fails on the presence of flags it doesn't handle. Until that bug
// is fixed, we need to remove any custom flag passed by the cleaner to the
// Crashpad process.
RemoveSwitchIfExisting(chrome_cleaner::kCrashHandlerSwitch, &argv);
RemoveSwitchIfExisting(chrome_cleaner::kTestLoggingURLSwitch, &argv);
RemoveSwitchIfExisting(chrome_cleaner::kCleanupIdSwitch, &argv);
// Disable rate-limiting until this is fixed:
// https://bugs.chromium.org/p/crashpad/issues/detail?id=23
argv.push_back(L"--no-rate-limit");
// |storage| must be declared before |argv_as_utf8|, to ensure it outlives
// |argv_as_utf8|, which will hold pointers into |storage|.
std::vector<std::string> storage;
std::unique_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
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;
return crashpad::HandlerMain(static_cast<int>(argv.size()),
argv_as_utf8.get(),
/* user_stream_sources */ nullptr);
}
base::string16 GetCrashReporterIPCPipeName() {
return g_is_connected_to_crash_handler
? GetCrashpadClient()->GetHandlerIPCPipe()
: base::string16();
}
void UseCrashReporter(const base::string16& ipc_pipe_name) {
DCHECK(!ipc_pipe_name.empty());
crashpad::CrashpadClient* crashpad_client = GetCrashpadClient();
if (!crashpad_client->SetHandlerIPCPipe(ipc_pipe_name)) {
LOG(DFATAL) << "Failed to set handler IPC pipe name: " << ipc_pipe_name;
} else {
g_is_connected_to_crash_handler = true;
LOG(INFO) << "Crash handler launched and ready.";
}
}
......@@ -9,10 +9,13 @@
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
#include "base/win/scoped_com_initializer.h"
#include "chrome/chrome_cleaner/crash/crash_client.h"
#include "chrome/chrome_cleaner/logging/scoped_logging.h"
#include "chrome/chrome_cleaner/os/rebooter.h"
#include "chrome/chrome_cleaner/os/secure_dll_loading.h"
#include "chrome/chrome_cleaner/os/system_util_cleaner.h"
#include "chrome/chrome_cleaner/os/task_scheduler.h"
#include "chrome/chrome_cleaner/settings/settings_types.h"
#include "chrome/chrome_cleaner/test/test_util.h"
#include "sandbox/win/src/sandbox_factory.h"
......@@ -24,6 +27,24 @@ bool IsSandboxedProcess() {
return is_sandboxed_process;
}
// base::TestSuite's Initialize method initializes logging differently than we
// do. This subclass ensures logging is properly initialized using ScopedLogging
// after base::TestSuite::Initialize has run.
class ChromeCleanerTestSuite : public base::TestSuite {
public:
// Inherit constructors.
using base::TestSuite::TestSuite;
protected:
void Initialize() override {
base::TestSuite::Initialize();
scoped_logging.reset(new chrome_cleaner::ScopedLogging(nullptr));
}
private:
std::unique_ptr<chrome_cleaner::ScopedLogging> scoped_logging;
};
} // namespace
int main(int argc, char** argv) {
......@@ -34,7 +55,7 @@ int main(int argc, char** argv) {
// affect the behaviour of functionality that's tested.
chrome_cleaner::EnableSecureDllLoading();
base::TestSuite test_suite(argc, argv);
ChromeCleanerTestSuite test_suite(argc, argv);
if (!chrome_cleaner::SetupTestConfigs())
return 1;
......@@ -60,6 +81,15 @@ int main(int argc, char** argv) {
success = chrome_cleaner::TaskScheduler::Initialize();
DCHECK(success) << "TaskScheduler::Initialize() failed.";
// Crash reporting must be initialized only once, so it cannot be
// initialized by individual tests or fixtures. Also, since crashpad does
// not actually enable uploading of crash reports in non-official builds
// (unless forced to by the --enable-crash-reporting flag) we don't need to
// disable crash reporting.
chrome_cleaner::CrashClient::GetInstance()->InitializeCrashReporting(
chrome_cleaner::CrashClient::Mode::CLEANER,
chrome_cleaner::SandboxType::kNonSandboxed);
}
// Some tests will fail if two tests try to launch test_process.exe
......
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