Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / crash_keys.cc
blobd172c464eefb4d0225c274f214e3939a65347498
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/crash_keys.h"
7 #include "base/command_line.h"
8 #include "base/format_macros.h"
9 #include "base/logging.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "content/public/common/content_switches.h"
16 #include "ipc/ipc_switches.h"
18 #if defined(OS_MACOSX)
19 #include "breakpad/src/common/simple_string_dictionary.h"
20 #elif defined(OS_WIN)
21 #include "breakpad/src/client/windows/common/ipc_protocol.h"
22 #elif defined(OS_CHROMEOS)
23 #include "chrome/common/chrome_switches.h"
24 #include "gpu/command_buffer/service/gpu_switches.h"
25 #include "ui/gl/gl_switches.h"
26 #endif
28 namespace crash_keys {
30 // The maximum lengths specified by breakpad include the trailing NULL, so
31 // the actual length of the string is one less.
32 #if defined(OS_MACOSX)
33 static const size_t kSingleChunkLength =
34 google_breakpad::SimpleStringDictionary::value_size - 1;
35 #elif defined(OS_WIN)
36 static const size_t kSingleChunkLength =
37 google_breakpad::CustomInfoEntry::kValueMaxLength - 1;
38 #else
39 static const size_t kSingleChunkLength = 63;
40 #endif
42 // Guarantees for crash key sizes.
43 static_assert(kSmallSize <= kSingleChunkLength,
44 "crash key chunk size too small");
45 #if defined(OS_MACOSX)
46 static_assert(kMediumSize <= kSingleChunkLength,
47 "mac has medium size crash key chunks");
48 #endif
50 const char kActiveURL[] = "url-chunk";
52 const char kFontKeyName[] = "font_key_name";
54 const char kSwitch[] = "switch-%" PRIuS;
55 const char kNumSwitches[] = "num-switches";
57 const char kExtensionID[] = "extension-%" PRIuS;
58 const char kNumExtensionsCount[] = "num-extensions";
60 const char kShutdownType[] = "shutdown-type";
62 #if !defined(OS_ANDROID)
63 const char kGPUVendorID[] = "gpu-venid";
64 const char kGPUDeviceID[] = "gpu-devid";
65 #endif
66 const char kGPUDriverVersion[] = "gpu-driver";
67 const char kGPUPixelShaderVersion[] = "gpu-psver";
68 const char kGPUVertexShaderVersion[] = "gpu-vsver";
69 #if defined(OS_MACOSX)
70 const char kGPUGLVersion[] = "gpu-glver";
71 #elif defined(OS_POSIX)
72 const char kGPUVendor[] = "gpu-gl-vendor";
73 const char kGPURenderer[] = "gpu-gl-renderer";
74 #endif
76 const char kPrinterInfo[] = "prn-info-%" PRIuS;
78 #if defined(OS_CHROMEOS)
79 const char kNumberOfUsers[] = "num-users";
80 #endif
82 #if defined(OS_MACOSX)
83 namespace mac {
85 const char kFirstNSException[] = "firstexception";
86 const char kFirstNSExceptionTrace[] = "firstexception_bt";
88 const char kLastNSException[] = "lastexception";
89 const char kLastNSExceptionTrace[] = "lastexception_bt";
91 const char kNSException[] = "nsexception";
92 const char kNSExceptionTrace[] = "nsexception_bt";
94 const char kSendAction[] = "sendaction";
96 } // namespace mac
97 #endif
99 #if defined(KASKO)
100 const char kKaskoGuid[] = "kasko-guid";
101 const char kKaskoEquivalentGuid[] = "kasko-equivalent-guid";
102 #endif
104 const char kViewCount[] = "view-count";
106 size_t RegisterChromeCrashKeys() {
107 // The following keys may be chunked by the underlying crash logging system,
108 // but ultimately constitute a single key-value pair.
109 base::debug::CrashKey fixed_keys[] = {
110 #if defined(OS_MACOSX)
111 { kMetricsClientId, kSmallSize },
112 #else
113 { kClientId, kSmallSize },
114 #endif
115 { kChannel, kSmallSize },
116 { kActiveURL, kLargeSize },
117 { kNumSwitches, kSmallSize },
118 { kNumVariations, kSmallSize },
119 { kVariations, kLargeSize },
120 { kNumExtensionsCount, kSmallSize },
121 { kShutdownType, kSmallSize },
122 #if !defined(OS_ANDROID)
123 { kGPUVendorID, kSmallSize },
124 { kGPUDeviceID, kSmallSize },
125 #endif
126 { kGPUDriverVersion, kSmallSize },
127 { kGPUPixelShaderVersion, kSmallSize },
128 { kGPUVertexShaderVersion, kSmallSize },
129 #if defined(OS_MACOSX)
130 { kGPUGLVersion, kSmallSize },
131 #elif defined(OS_POSIX)
132 { kGPUVendor, kSmallSize },
133 { kGPURenderer, kSmallSize },
134 #endif
136 // content/:
137 { "discardable-memory-allocated", kSmallSize },
138 { "discardable-memory-free", kSmallSize },
139 { kFontKeyName, kSmallSize},
140 { "ppapi_path", kMediumSize },
141 { "subresource_url", kLargeSize },
142 { "total-discardable-memory-allocated", kSmallSize },
143 #if defined(OS_CHROMEOS)
144 { kNumberOfUsers, kSmallSize },
145 #endif
146 #if defined(OS_MACOSX)
147 { mac::kFirstNSException, kMediumSize },
148 { mac::kFirstNSExceptionTrace, kMediumSize },
149 { mac::kLastNSException, kMediumSize },
150 { mac::kLastNSExceptionTrace, kMediumSize },
151 { mac::kNSException, kMediumSize },
152 { mac::kNSExceptionTrace, kMediumSize },
153 { mac::kSendAction, kMediumSize },
154 { mac::kZombie, kMediumSize },
155 { mac::kZombieTrace, kMediumSize },
156 // content/:
157 { "channel_error_bt", kMediumSize },
158 { "remove_route_bt", kMediumSize },
159 { "rwhvm_window", kMediumSize },
160 // media/:
161 { "VideoCaptureDeviceQTKit", kSmallSize },
162 #endif
163 #if defined(KASKO)
164 { kKaskoGuid, kSmallSize },
165 { kKaskoEquivalentGuid, kSmallSize },
166 #endif
167 { kBug464926CrashKey, kSmallSize },
168 { kViewCount, kSmallSize },
171 // This dynamic set of keys is used for sets of key value pairs when gathering
172 // a collection of data, like command line switches or extension IDs.
173 std::vector<base::debug::CrashKey> keys(
174 fixed_keys, fixed_keys + arraysize(fixed_keys));
176 // Register the switches.
178 // The fixed_keys names are string constants. Use static storage for
179 // formatted key names as well, since they will persist for the duration of
180 // the program.
181 static char formatted_keys[kSwitchesMaxCount][sizeof(kSwitch) + 1] =
182 {{ 0 }};
183 const size_t formatted_key_len = sizeof(formatted_keys[0]);
184 for (size_t i = 0; i < kSwitchesMaxCount; ++i) {
185 // Name the keys using 1-based indexing.
186 int n = base::snprintf(
187 formatted_keys[i], formatted_key_len, kSwitch, i + 1);
188 DCHECK_GT(n, 0);
189 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
190 keys.push_back(crash_key);
194 // Register the extension IDs.
196 static char formatted_keys[kExtensionIDMaxCount][sizeof(kExtensionID) + 1] =
197 {{ 0 }};
198 const size_t formatted_key_len = sizeof(formatted_keys[0]);
199 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
200 int n = base::snprintf(
201 formatted_keys[i], formatted_key_len, kExtensionID, i + 1);
202 DCHECK_GT(n, 0);
203 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
204 keys.push_back(crash_key);
208 // Register the printer info.
210 static char formatted_keys[kPrinterInfoCount][sizeof(kPrinterInfo) + 1] =
211 {{ 0 }};
212 const size_t formatted_key_len = sizeof(formatted_keys[0]);
213 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
214 // Key names are 1-indexed.
215 int n = base::snprintf(
216 formatted_keys[i], formatted_key_len, kPrinterInfo, i + 1);
217 DCHECK_GT(n, 0);
218 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
219 keys.push_back(crash_key);
223 return base::debug::InitCrashKeys(&keys.at(0), keys.size(),
224 kSingleChunkLength);
227 static bool IsBoringSwitch(const std::string& flag) {
228 static const char* const kIgnoreSwitches[] = {
229 switches::kEnableLogging,
230 switches::kFlagSwitchesBegin,
231 switches::kFlagSwitchesEnd,
232 switches::kLoggingLevel,
233 #if defined(OS_WIN)
234 // This file is linked into both chrome.dll and chrome.exe. However //ipc
235 // is only in the .dll, so this needs to be a literal rather than the
236 // constant.
237 "channel", // switches::kProcessChannelID
238 #else
239 switches::kProcessChannelID,
240 #endif
241 switches::kProcessType,
242 switches::kV,
243 switches::kVModule,
244 #if defined(OS_WIN)
245 switches::kForceFieldTrials,
246 switches::kPluginPath,
247 #elif defined(OS_MACOSX)
248 switches::kMetricsClientID,
249 #elif defined(OS_CHROMEOS)
250 switches::kPpapiFlashArgs,
251 switches::kPpapiFlashPath,
252 switches::kRegisterPepperPlugins,
253 switches::kUIPrioritizeInGpuProcess,
254 switches::kUseGL,
255 switches::kUserDataDir,
256 // Cros/CC flags are specified as raw strings to avoid dependency.
257 "child-wallpaper-large",
258 "child-wallpaper-small",
259 "default-wallpaper-large",
260 "default-wallpaper-small",
261 "guest-wallpaper-large",
262 "guest-wallpaper-small",
263 "enterprise-enable-forced-re-enrollment",
264 "enterprise-enrollment-initial-modulus",
265 "enterprise-enrollment-modulus-limit",
266 "login-profile",
267 "login-user",
268 "max-unused-resource-memory-usage-percentage",
269 "termination-message-file",
270 "use-cras",
271 #endif
274 #if defined(OS_WIN)
275 // Just about everything has this, don't bother.
276 if (base::StartsWith(flag, "/prefetch:", base::CompareCase::SENSITIVE))
277 return true;
278 #endif
280 if (!base::StartsWith(flag, "--", base::CompareCase::SENSITIVE))
281 return false;
282 size_t end = flag.find("=");
283 size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
284 for (size_t i = 0; i < arraysize(kIgnoreSwitches); ++i) {
285 if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
286 return true;
288 return false;
291 void SetSwitchesFromCommandLine(const base::CommandLine* command_line) {
292 DCHECK(command_line);
293 if (!command_line)
294 return;
296 const base::CommandLine::StringVector& argv = command_line->argv();
298 // Set the number of switches in case size > kNumSwitches.
299 base::debug::SetCrashKeyValue(kNumSwitches,
300 base::StringPrintf("%" PRIuS, argv.size() - 1));
302 size_t key_i = 1; // Key names are 1-indexed.
304 // Go through the argv, skipping the exec path.
305 for (size_t i = 1; i < argv.size(); ++i) {
306 #if defined(OS_WIN)
307 std::string switch_str = base::WideToUTF8(argv[i]);
308 #else
309 std::string switch_str = argv[i];
310 #endif
312 // Skip uninteresting switches.
313 if (IsBoringSwitch(switch_str))
314 continue;
316 // Stop if there are too many switches.
317 if (i > crash_keys::kSwitchesMaxCount)
318 break;
320 std::string key = base::StringPrintf(kSwitch, key_i++);
321 base::debug::SetCrashKeyValue(key, switch_str);
324 // Clear any remaining switches.
325 for (; key_i <= kSwitchesMaxCount; ++key_i) {
326 base::debug::ClearCrashKey(base::StringPrintf(kSwitch, key_i));
330 void SetActiveExtensions(const std::set<std::string>& extensions) {
331 base::debug::SetCrashKeyValue(kNumExtensionsCount,
332 base::StringPrintf("%" PRIuS, extensions.size()));
334 std::set<std::string>::const_iterator it = extensions.begin();
335 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
336 std::string key = base::StringPrintf(kExtensionID, i + 1);
337 if (it == extensions.end()) {
338 base::debug::ClearCrashKey(key);
339 } else {
340 base::debug::SetCrashKeyValue(key, *it);
341 ++it;
346 ScopedPrinterInfo::ScopedPrinterInfo(const base::StringPiece& data) {
347 std::vector<std::string> info = base::SplitString(
348 data.as_string(), ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
349 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
350 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
351 std::string value;
352 if (i < info.size())
353 value = info[i];
354 base::debug::SetCrashKeyValue(key, value);
358 ScopedPrinterInfo::~ScopedPrinterInfo() {
359 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
360 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
361 base::debug::ClearCrashKey(key);
365 } // namespace crash_keys