Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / common / crash_keys.cc
blobdfe0f425b16928195c6448753c34cd0e7eb1a6c9
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"
15 #if defined(OS_MACOSX)
16 #include "breakpad/src/common/simple_string_dictionary.h"
17 #elif defined(OS_WIN)
18 #include "breakpad/src/client/windows/common/ipc_protocol.h"
19 #elif defined(OS_CHROMEOS)
20 #include "chrome/common/chrome_switches.h"
21 #include "gpu/command_buffer/service/gpu_switches.h"
22 #include "ui/gl/gl_switches.h"
23 #endif
25 namespace crash_keys {
27 // A small crash key, guaranteed to never be split into multiple pieces.
28 const size_t kSmallSize = 63;
30 // A medium crash key, which will be chunked on certain platforms but not
31 // others. Guaranteed to never be more than four chunks.
32 const size_t kMediumSize = kSmallSize * 4;
34 // A large crash key, which will be chunked on all platforms. This should be
35 // used sparingly.
36 const size_t kLargeSize = kSmallSize * 16;
38 // The maximum lengths specified by breakpad include the trailing NULL, so
39 // the actual length of the string is one less.
40 #if defined(OS_MACOSX)
41 static const size_t kSingleChunkLength =
42 google_breakpad::SimpleStringDictionary::value_size - 1;
43 #elif defined(OS_WIN)
44 static const size_t kSingleChunkLength =
45 google_breakpad::CustomInfoEntry::kValueMaxLength - 1;
46 #else
47 static const size_t kSingleChunkLength = 63;
48 #endif
50 // Guarantees for crash key sizes.
51 static_assert(kSmallSize <= kSingleChunkLength,
52 "crash key chunk size too small");
53 #if defined(OS_MACOSX)
54 static_assert(kMediumSize <= kSingleChunkLength,
55 "mac has medium size crash key chunks");
56 #endif
58 #if defined(OS_MACOSX)
59 // Crashpad owns the "guid" key. Chrome's metrics client ID is a separate ID
60 // carried in a distinct "metrics_client_id" field.
61 const char kMetricsClientId[] = "metrics_client_id";
62 #else
63 const char kClientId[] = "guid";
64 #endif
66 const char kChannel[] = "channel";
68 const char kActiveURL[] = "url-chunk";
70 const char kFontKeyName[] = "font_key_name";
72 const char kSwitch[] = "switch-%" PRIuS;
73 const char kNumSwitches[] = "num-switches";
75 const char kNumVariations[] = "num-experiments";
76 const char kVariations[] = "variations";
78 const char kExtensionID[] = "extension-%" PRIuS;
79 const char kNumExtensionsCount[] = "num-extensions";
81 const char kShutdownType[] = "shutdown-type";
83 #if !defined(OS_ANDROID)
84 const char kGPUVendorID[] = "gpu-venid";
85 const char kGPUDeviceID[] = "gpu-devid";
86 #endif
87 const char kGPUDriverVersion[] = "gpu-driver";
88 const char kGPUPixelShaderVersion[] = "gpu-psver";
89 const char kGPUVertexShaderVersion[] = "gpu-vsver";
90 #if defined(OS_MACOSX)
91 const char kGPUGLVersion[] = "gpu-glver";
92 #elif defined(OS_POSIX)
93 const char kGPUVendor[] = "gpu-gl-vendor";
94 const char kGPURenderer[] = "gpu-gl-renderer";
95 #endif
97 const char kPrinterInfo[] = "prn-info-%" PRIuS;
99 #if defined(OS_CHROMEOS)
100 const char kNumberOfUsers[] = "num-users";
101 #endif
103 #if defined(OS_MACOSX)
104 namespace mac {
106 const char kFirstNSException[] = "firstexception";
107 const char kFirstNSExceptionTrace[] = "firstexception_bt";
109 const char kLastNSException[] = "lastexception";
110 const char kLastNSExceptionTrace[] = "lastexception_bt";
112 const char kNSException[] = "nsexception";
113 const char kNSExceptionTrace[] = "nsexception_bt";
115 const char kSendAction[] = "sendaction";
117 const char kZombie[] = "zombie";
118 const char kZombieTrace[] = "zombie_dealloc_bt";
120 } // namespace mac
121 #endif
123 #if defined(KASKO)
124 const char kKaskoGuid[] = "kasko-guid";
125 const char kKaskoEquivalentGuid[] = "kasko-equivalent-guid";
126 #endif
128 size_t RegisterChromeCrashKeys() {
129 // The following keys may be chunked by the underlying crash logging system,
130 // but ultimately constitute a single key-value pair.
131 base::debug::CrashKey fixed_keys[] = {
132 #if defined(OS_MACOSX)
133 { kMetricsClientId, kSmallSize },
134 #else
135 { kClientId, kSmallSize },
136 #endif
137 { kChannel, kSmallSize },
138 { kActiveURL, kLargeSize },
139 { kNumSwitches, kSmallSize },
140 { kNumVariations, kSmallSize },
141 { kVariations, kLargeSize },
142 { kNumExtensionsCount, kSmallSize },
143 { kShutdownType, kSmallSize },
144 #if !defined(OS_ANDROID)
145 { kGPUVendorID, kSmallSize },
146 { kGPUDeviceID, kSmallSize },
147 #endif
148 { kGPUDriverVersion, kSmallSize },
149 { kGPUPixelShaderVersion, kSmallSize },
150 { kGPUVertexShaderVersion, kSmallSize },
151 #if defined(OS_MACOSX)
152 { kGPUGLVersion, kSmallSize },
153 #elif defined(OS_POSIX)
154 { kGPUVendor, kSmallSize },
155 { kGPURenderer, kSmallSize },
156 #endif
158 // content/:
159 { "discardable-memory-allocated", kSmallSize },
160 { "discardable-memory-free", kSmallSize },
161 { kFontKeyName, kSmallSize},
162 { "ppapi_path", kMediumSize },
163 { "subresource_url", kLargeSize },
164 { "total-discardable-memory-allocated", kSmallSize },
165 #if defined(OS_CHROMEOS)
166 { kNumberOfUsers, kSmallSize },
167 #endif
168 #if defined(OS_MACOSX)
169 { mac::kFirstNSException, kMediumSize },
170 { mac::kFirstNSExceptionTrace, kMediumSize },
171 { mac::kLastNSException, kMediumSize },
172 { mac::kLastNSExceptionTrace, kMediumSize },
173 { mac::kNSException, kMediumSize },
174 { mac::kNSExceptionTrace, kMediumSize },
175 { mac::kSendAction, kMediumSize },
176 { mac::kZombie, kMediumSize },
177 { mac::kZombieTrace, kMediumSize },
178 // content/:
179 { "channel_error_bt", kMediumSize },
180 { "remove_route_bt", kMediumSize },
181 { "rwhvm_window", kMediumSize },
182 // media/:
183 { "VideoCaptureDeviceQTKit", kSmallSize },
184 #endif
185 #if defined(KASKO)
186 { kKaskoGuid, kSmallSize },
187 { kKaskoEquivalentGuid, kSmallSize },
188 #endif
191 // This dynamic set of keys is used for sets of key value pairs when gathering
192 // a collection of data, like command line switches or extension IDs.
193 std::vector<base::debug::CrashKey> keys(
194 fixed_keys, fixed_keys + arraysize(fixed_keys));
196 // Register the switches.
198 // The fixed_keys names are string constants. Use static storage for
199 // formatted key names as well, since they will persist for the duration of
200 // the program.
201 static char formatted_keys[kSwitchesMaxCount][sizeof(kSwitch) + 1] =
202 {{ 0 }};
203 const size_t formatted_key_len = sizeof(formatted_keys[0]);
204 for (size_t i = 0; i < kSwitchesMaxCount; ++i) {
205 // Name the keys using 1-based indexing.
206 int n = base::snprintf(
207 formatted_keys[i], formatted_key_len, kSwitch, i + 1);
208 DCHECK_GT(n, 0);
209 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
210 keys.push_back(crash_key);
214 // Register the extension IDs.
216 static char formatted_keys[kExtensionIDMaxCount][sizeof(kExtensionID) + 1] =
217 {{ 0 }};
218 const size_t formatted_key_len = sizeof(formatted_keys[0]);
219 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
220 int n = base::snprintf(
221 formatted_keys[i], formatted_key_len, kExtensionID, i + 1);
222 DCHECK_GT(n, 0);
223 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
224 keys.push_back(crash_key);
228 // Register the printer info.
230 static char formatted_keys[kPrinterInfoCount][sizeof(kPrinterInfo) + 1] =
231 {{ 0 }};
232 const size_t formatted_key_len = sizeof(formatted_keys[0]);
233 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
234 // Key names are 1-indexed.
235 int n = base::snprintf(
236 formatted_keys[i], formatted_key_len, kPrinterInfo, i + 1);
237 DCHECK_GT(n, 0);
238 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
239 keys.push_back(crash_key);
243 return base::debug::InitCrashKeys(&keys.at(0), keys.size(),
244 kSingleChunkLength);
247 void SetMetricsClientIdFromGUID(const std::string& metrics_client_guid) {
248 std::string stripped_guid(metrics_client_guid);
249 // Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY.
250 ReplaceSubstringsAfterOffset(&stripped_guid, 0, "-", "");
251 if (stripped_guid.empty())
252 return;
254 #if defined(OS_MACOSX)
255 // The crash client ID is maintained by Crashpad and is distinct from the
256 // metrics client ID, which is carried in its own key.
257 base::debug::SetCrashKeyValue(kMetricsClientId, stripped_guid);
258 #else
259 // The crash client ID is set by the application when Breakpad is in use.
260 // The same ID as the metrics client ID is used.
261 base::debug::SetCrashKeyValue(kClientId, stripped_guid);
262 #endif
265 void ClearMetricsClientId() {
266 #if defined(OS_MACOSX)
267 // Crashpad always monitors for crashes, but doesn't upload them when
268 // crash reporting is disabled. The preference to upload crash reports is
269 // linked to the preference for metrics reporting. When metrics reporting is
270 // disabled, don't put the metrics client ID into crash dumps. This way, crash
271 // reports that are saved but not uploaded will not have a metrics client ID
272 // from the time that metrics reporting was disabled even if they are uploaded
273 // by user action at a later date.
275 // Breakpad cannot be enabled or disabled without an application restart, and
276 // it needs to use the metrics client ID as its stable crash client ID, so
277 // leave its client ID intact even when metrics reporting is disabled while
278 // the application is running.
279 base::debug::ClearCrashKey(kMetricsClientId);
280 #endif
283 static bool IsBoringSwitch(const std::string& flag) {
284 #if defined(OS_WIN)
285 return StartsWithASCII(flag, "--channel=", true) ||
287 // No point to including this since we already have a ptype field.
288 StartsWithASCII(flag, "--type=", true) ||
290 // Not particularly interesting
291 StartsWithASCII(flag, "--flash-broker=", true) ||
293 // Just about everything has this, don't bother.
294 StartsWithASCII(flag, "/prefetch:", true) ||
296 // We handle the plugin path separately since it is usually too big
297 // to fit in the switches (limited to 63 characters).
298 StartsWithASCII(flag, "--plugin-path=", true) ||
300 // This is too big so we end up truncating it anyway.
301 StartsWithASCII(flag, "--force-fieldtrials=", true) ||
303 // These surround the flags that were added by about:flags, it lets
304 // you distinguish which flags were added manually via the command
305 // line versus those added through about:flags. For the most part
306 // we don't care how an option was enabled, so we strip these.
307 // (If you need to know can always look at the PEB).
308 flag == "--flag-switches-begin" ||
309 flag == "--flag-switches-end";
310 #elif defined(OS_MACOSX)
311 // These are carried in their own fields.
312 return StartsWithASCII(flag, "--channel=", true) ||
313 StartsWithASCII(flag, "--type=", true) ||
314 StartsWithASCII(flag, "--metrics-client-id=", true);
315 #elif defined(OS_CHROMEOS)
316 static const char* const kIgnoreSwitches[] = {
317 ::switches::kEnableLogging,
318 ::switches::kFlagSwitchesBegin,
319 ::switches::kFlagSwitchesEnd,
320 ::switches::kLoggingLevel,
321 ::switches::kPpapiFlashArgs,
322 ::switches::kPpapiFlashPath,
323 ::switches::kRegisterPepperPlugins,
324 ::switches::kUIPrioritizeInGpuProcess,
325 ::switches::kUseGL,
326 ::switches::kUserDataDir,
327 ::switches::kV,
328 ::switches::kVModule,
329 // Cros/CC flgas are specified as raw strings to avoid dependency.
330 "child-wallpaper-large",
331 "child-wallpaper-small",
332 "default-wallpaper-large",
333 "default-wallpaper-small",
334 "guest-wallpaper-large",
335 "guest-wallpaper-small",
336 "enterprise-enable-forced-re-enrollment",
337 "enterprise-enrollment-initial-modulus",
338 "enterprise-enrollment-modulus-limit",
339 "login-profile",
340 "login-user",
341 "max-tiles-for-interest-area",
342 "max-unused-resource-memory-usage-percentage",
343 "termination-message-file",
344 "use-cras",
346 if (!StartsWithASCII(flag, "--", true))
347 return false;
348 std::size_t end = flag.find("=");
349 int len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
350 for (size_t i = 0; i < arraysize(kIgnoreSwitches); ++i) {
351 if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
352 return true;
354 return false;
355 #else
356 return false;
357 #endif
360 void SetSwitchesFromCommandLine(const base::CommandLine* command_line) {
361 DCHECK(command_line);
362 if (!command_line)
363 return;
365 const base::CommandLine::StringVector& argv = command_line->argv();
367 // Set the number of switches in case size > kNumSwitches.
368 base::debug::SetCrashKeyValue(kNumSwitches,
369 base::StringPrintf("%" PRIuS, argv.size() - 1));
371 size_t key_i = 1; // Key names are 1-indexed.
373 // Go through the argv, skipping the exec path.
374 for (size_t i = 1; i < argv.size(); ++i) {
375 #if defined(OS_WIN)
376 std::string switch_str = base::WideToUTF8(argv[i]);
377 #else
378 std::string switch_str = argv[i];
379 #endif
381 // Skip uninteresting switches.
382 if (IsBoringSwitch(switch_str))
383 continue;
385 // Stop if there are too many switches.
386 if (i > crash_keys::kSwitchesMaxCount)
387 break;
389 std::string key = base::StringPrintf(kSwitch, key_i++);
390 base::debug::SetCrashKeyValue(key, switch_str);
393 // Clear any remaining switches.
394 for (; key_i <= kSwitchesMaxCount; ++key_i) {
395 base::debug::ClearCrashKey(base::StringPrintf(kSwitch, key_i));
399 void SetVariationsList(const std::vector<std::string>& variations) {
400 base::debug::SetCrashKeyValue(kNumVariations,
401 base::StringPrintf("%" PRIuS, variations.size()));
403 std::string variations_string;
404 variations_string.reserve(kLargeSize);
406 for (size_t i = 0; i < variations.size(); ++i) {
407 const std::string& variation = variations[i];
408 // Do not truncate an individual experiment.
409 if (variations_string.size() + variation.size() >= kLargeSize)
410 break;
411 variations_string += variation;
412 variations_string += ",";
415 base::debug::SetCrashKeyValue(kVariations, variations_string);
418 void SetActiveExtensions(const std::set<std::string>& extensions) {
419 base::debug::SetCrashKeyValue(kNumExtensionsCount,
420 base::StringPrintf("%" PRIuS, extensions.size()));
422 std::set<std::string>::const_iterator it = extensions.begin();
423 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
424 std::string key = base::StringPrintf(kExtensionID, i + 1);
425 if (it == extensions.end()) {
426 base::debug::ClearCrashKey(key);
427 } else {
428 base::debug::SetCrashKeyValue(key, *it);
429 ++it;
434 ScopedPrinterInfo::ScopedPrinterInfo(const base::StringPiece& data) {
435 std::vector<std::string> info;
436 base::SplitString(data.as_string(), ';', &info);
437 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
438 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
439 std::string value;
440 if (i < info.size())
441 value = info[i];
442 base::debug::SetCrashKeyValue(key, value);
446 ScopedPrinterInfo::~ScopedPrinterInfo() {
447 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
448 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
449 base::debug::ClearCrashKey(key);
453 } // namespace crash_keys