1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// 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/core/common/crash_keys.h"
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
namespace crash_keys {
#if defined(OS_MACOSX)
// 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
const char kChannel[] = "channel";
const char kNumVariations[] = "num-experiments";
const char kVariations[] = "variations";
const char kSwitchFormat[] = "switch-%" PRIuS;
const char kNumSwitches[] = "num-switches";
const char kBug464926CrashKey[] = "bug-464926-info";
#if defined(OS_MACOSX)
namespace mac {
const char kZombie[] = "zombie";
const char kZombieTrace[] = "zombie_dealloc_bt";
} // namespace mac
#endif
void SetMetricsClientIdFromGUID(const std::string& metrics_client_guid) {
std::string stripped_guid(metrics_client_guid);
// Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY.
base::ReplaceSubstringsAfterOffset(
&stripped_guid, 0, "-", base::StringPiece());
if (stripped_guid.empty())
return;
#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);
#else
// The crash client ID is set by the application when Breakpad is in use.
// The same ID as the metrics client ID is used.
base::debug::SetCrashKeyValue(kClientId, stripped_guid);
#endif
}
void ClearMetricsClientId() {
#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
// disabled, don't put the metrics client ID into crash dumps. This way, crash
// reports that are saved but not uploaded will not have a metrics client ID
// from the time that metrics reporting was disabled even if they are uploaded
// by user action at a later date.
//
// Breakpad cannot be enabled or disabled without an application restart, and
// it needs to use the metrics client ID as its stable crash client ID, so
// leave its client ID intact even when metrics reporting is disabled while
// the application is running.
base::debug::ClearCrashKey(kMetricsClientId);
#endif
}
void SetVariationsList(const std::vector<std::string>& variations) {
base::debug::SetCrashKeyValue(kNumVariations,
base::StringPrintf("%" PRIuS, variations.size()));
std::string variations_string;
variations_string.reserve(kLargeSize);
for (size_t i = 0; i < variations.size(); ++i) {
const std::string& variation = variations[i];
// Do not truncate an individual experiment.
if (variations_string.size() + variation.size() >= kLargeSize)
break;
variations_string += variation;
variations_string += ",";
}
base::debug::SetCrashKeyValue(kVariations, variations_string);
}
void GetCrashKeysForCommandLineSwitches(
std::vector<base::debug::CrashKey>* keys) {
DCHECK(keys);
base::debug::CrashKey crash_key = { kNumSwitches, kSmallSize };
keys->push_back(crash_key);
// Use static storage for formatted key names, since they will persist for
// the duration of the program.
static char formatted_keys[kSwitchesMaxCount][sizeof(kSwitchFormat) + 1] =
{{ 0 }};
const size_t formatted_key_len = sizeof(formatted_keys[0]);
// sizeof(kSwitchFormat) is platform-dependent, so make sure formatted_keys
// actually have space for a 2-digit switch number plus null-terminator.
static_assert(formatted_key_len >= 10,
"insufficient space for \"switch-NN\"");
for (size_t i = 0; i < kSwitchesMaxCount; ++i) {
// Name the keys using 1-based indexing.
int n = base::snprintf(formatted_keys[i], formatted_key_len, kSwitchFormat,
i + 1);
DCHECK_GT(n, 0);
base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
keys->push_back(crash_key);
}
}
void SetSwitchesFromCommandLine(const base::CommandLine& command_line,
SwitchFilterFunction skip_filter) {
const base::CommandLine::StringVector& argv = command_line.argv();
// Set the number of switches in case size > kNumSwitches.
base::debug::SetCrashKeyValue(kNumSwitches,
base::StringPrintf("%" PRIuS, argv.size() - 1));
size_t key_i = 1; // Key names are 1-indexed.
// Go through the argv, skipping the exec path. Stop if there are too many
// switches to hold in crash keys.
for (size_t i = 1; i < argv.size() && key_i <= crash_keys::kSwitchesMaxCount;
++i) {
#if defined(OS_WIN)
std::string switch_str = base::WideToUTF8(argv[i]);
#else
std::string switch_str = argv[i];
#endif
// Skip uninteresting switches.
if (skip_filter && (*skip_filter)(switch_str))
continue;
std::string key = base::StringPrintf(kSwitchFormat, key_i++);
base::debug::SetCrashKeyValue(key, switch_str);
}
// Clear any remaining switches.
for (; key_i <= kSwitchesMaxCount; ++key_i)
base::debug::ClearCrashKey(base::StringPrintf(kSwitchFormat, key_i));
}
} // namespace crash_keys
|