blob: 7bfd32b40bd3ead188c0d2437a86f789437bde89 [file] [log] [blame]
// 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 "chrome/installer/setup/installer_crash_reporting.h"
#include <iterator>
#include <memory>
#include <vector>
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/debug/leak_annotations.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/version.h"
#include "base/win/registry.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/install_static/install_details.h"
#include "chrome/installer/setup/installer_crash_reporter_client.h"
#include "chrome/installer/setup/installer_state.h"
#include "chrome/installer/util/google_update_settings.h"
#include "components/crash/content/app/crash_keys_win.h"
#include "components/crash/content/app/crashpad.h"
#include "components/crash/core/common/crash_keys.h"
namespace installer {
namespace {
// Crash Keys
const char kApValue[] = "ap";
const char kCohortName[] = "cohort-name";
const char kCurrentVersion[] = "current-version";
const char kIsSystemLevel[] = "system-level";
const char kOperation[] = "operation";
const char kStateKey[] = "state-key";
const char *OperationToString(InstallerState::Operation operation) {
switch (operation) {
case InstallerState::SINGLE_INSTALL_OR_UPDATE:
return "single-install-or-update";
case InstallerState::UNINSTALL:
return "uninstall";
case InstallerState::UNINITIALIZED:
// Fall out of switch.
break;
}
NOTREACHED();
return "";
}
// Retrieve the SYSTEM version of TEMP. We do this instead of GetTempPath so
// that both elevated and SYSTEM runs share the same directory.
bool GetSystemTemp(base::FilePath* temp) {
base::win::RegKey reg_key(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
KEY_READ);
std::wstring temp_wstring; // presubmit: allow wstring
bool success = reg_key.ReadValue(L"TEMP", &temp_wstring) == ERROR_SUCCESS;
if (success)
*temp = base::FilePath(temp_wstring); // presubmit: allow wstring
return success;
}
} // namespace
void ConfigureCrashReporting(const InstallerState& installer_state) {
// This is inspired by work done in various parts of Chrome startup to connect
// to the crash service. Since the installer does not split its work between
// a stub .exe and a main .dll, crash reporting can be configured in one place
// right here.
// Create the crash client and install it (a la MainDllLoader::Launch).
InstallerCrashReporterClient* crash_client =
new InstallerCrashReporterClient(!installer_state.system_install());
ANNOTATE_LEAKING_OBJECT_PTR(crash_client);
crash_reporter::SetCrashReporterClient(crash_client);
if (installer_state.system_install()) {
base::FilePath temp_dir;
if (GetSystemTemp(&temp_dir)) {
base::FilePath crash_dir = temp_dir.Append(FILE_PATH_LITERAL("Crashpad"));
PathService::OverrideAndCreateIfNeeded(chrome::DIR_CRASH_DUMPS, crash_dir,
true, true);
} else {
// Failed to get a temp dir, something's gone wrong.
return;
}
}
crash_reporter::InitializeCrashpadWithEmbeddedHandler(true,
"Chrome Installer");
// Set up the metrics client id (a la child_process_logging::Init()).
std::unique_ptr<metrics::ClientInfo> client_info =
GoogleUpdateSettings::LoadMetricsClientInfo();
if (client_info)
crash_keys::SetMetricsClientIdFromGUID(client_info->client_id);
}
size_t RegisterCrashKeys() {
static constexpr base::debug::CrashKey kFixedKeys[] = {
{crash_keys::kMetricsClientId, crash_keys::kSmallSize},
{kApValue, crash_keys::kSmallSize},
{kCohortName, crash_keys::kSmallSize},
{kCurrentVersion, crash_keys::kSmallSize},
{kIsSystemLevel, crash_keys::kSmallSize},
{kOperation, crash_keys::kSmallSize},
// This is a Windows registry key, which maxes out at 255 chars.
// (kMediumSize actually maxes out at 252 chars on Windows, but
// potentially truncating such a small amount is a fair tradeoff compared
// to using kLargeSize, which is wasteful.)
{kStateKey, crash_keys::kMediumSize},
};
std::vector<base::debug::CrashKey> keys(std::begin(kFixedKeys),
std::end(kFixedKeys));
crash_keys::GetCrashKeysForCommandLineSwitches(&keys);
return base::debug::InitCrashKeys(keys.data(), keys.size(),
crash_keys::kChunkMaxLength);
}
void SetInitialCrashKeys(const InstallerState& state) {
using base::debug::SetCrashKeyValue;
SetCrashKeyValue(kOperation, OperationToString(state.operation()));
SetCrashKeyValue(kIsSystemLevel, state.system_install() ? "true" : "false");
const base::string16 state_key = state.state_key();
if (!state_key.empty())
SetCrashKeyValue(kStateKey, base::UTF16ToUTF8(state_key));
// Set crash keys containing the registry values used to determine Chrome's
// update channel at process startup; see https://crbug.com/579504.
const auto& details = install_static::InstallDetails::Get();
base::debug::SetCrashKeyValue(kApValue,
base::UTF16ToUTF8(details.update_ap()));
base::debug::SetCrashKeyValue(
kCohortName, base::UTF16ToUTF8(details.update_cohort_name()));
}
void SetCrashKeysFromCommandLine(const base::CommandLine& command_line) {
crash_keys::SetSwitchesFromCommandLine(command_line, nullptr);
}
void SetCurrentVersionCrashKey(const base::Version* current_version) {
if (current_version) {
base::debug::SetCrashKeyValue(kCurrentVersion,
current_version->GetString());
} else {
base::debug::ClearCrashKey(kCurrentVersion);
}
}
} // namespace installer