Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / crash_keys.cc
blob2bf2bb2a47bac505c61a621d2ae9160bb78fd5c3
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/installer/util/google_update_settings.h"
16 #if defined(OS_MACOSX)
17 #include "breakpad/src/common/simple_string_dictionary.h"
18 #elif defined(OS_WIN)
19 #include "breakpad/src/client/windows/common/ipc_protocol.h"
20 #endif
22 namespace crash_keys {
24 // A small crash key, guaranteed to never be split into multiple pieces.
25 const size_t kSmallSize = 63;
27 // A medium crash key, which will be chunked on certain platforms but not
28 // others. Guaranteed to never be more than four chunks.
29 const size_t kMediumSize = kSmallSize * 4;
31 // A large crash key, which will be chunked on all platforms. This should be
32 // used sparingly.
33 const size_t kLargeSize = kSmallSize * 16;
35 // The maximum lengths specified by breakpad include the trailing NULL, so
36 // the actual length of the string is one less.
37 #if defined(OS_MACOSX)
38 static const size_t kSingleChunkLength =
39 google_breakpad::SimpleStringDictionary::value_size - 1;
40 #elif defined(OS_WIN)
41 static const size_t kSingleChunkLength =
42 google_breakpad::CustomInfoEntry::kValueMaxLength - 1;
43 #else
44 static const size_t kSingleChunkLength = 63;
45 #endif
47 // Guarantees for crash key sizes.
48 COMPILE_ASSERT(kSmallSize <= kSingleChunkLength,
49 crash_key_chunk_size_too_small);
50 #if defined(OS_MACOSX)
51 COMPILE_ASSERT(kMediumSize <= kSingleChunkLength,
52 mac_has_medium_size_crash_key_chunks);
53 #endif
55 const char kClientID[] = "guid";
57 const char kChannel[] = "channel";
59 const char kActiveURL[] = "url-chunk";
61 const char kSwitch[] = "switch-%" PRIuS;
62 const char kNumSwitches[] = "num-switches";
64 const char kNumVariations[] = "num-experiments";
65 const char kVariations[] = "variations";
67 const char kExtensionID[] = "extension-%" PRIuS;
68 const char kNumExtensionsCount[] = "num-extensions";
70 const char kNumberOfViews[] = "num-views";
72 #if !defined(OS_ANDROID)
73 const char kGPUVendorID[] = "gpu-venid";
74 const char kGPUDeviceID[] = "gpu-devid";
75 #endif
76 const char kGPUDriverVersion[] = "gpu-driver";
77 const char kGPUPixelShaderVersion[] = "gpu-psver";
78 const char kGPUVertexShaderVersion[] = "gpu-vsver";
79 #if defined(OS_MACOSX)
80 const char kGPUGLVersion[] = "gpu-glver";
81 #elif defined(OS_POSIX)
82 const char kGPUVendor[] = "gpu-gl-vendor";
83 const char kGPURenderer[] = "gpu-gl-renderer";
84 #endif
86 const char kPrinterInfo[] = "prn-info-%" PRIuS;
88 #if defined(OS_CHROMEOS)
89 const char kNumberOfUsers[] = "num-users";
90 #endif
92 #if defined(OS_MACOSX)
93 namespace mac {
95 const char kFirstNSException[] = "firstexception";
96 const char kFirstNSExceptionTrace[] = "firstexception_bt";
98 const char kLastNSException[] = "lastexception";
99 const char kLastNSExceptionTrace[] = "lastexception_bt";
101 const char kNSException[] = "nsexception";
102 const char kNSExceptionTrace[] = "nsexception_bt";
104 const char kSendAction[] = "sendaction";
106 const char kZombie[] = "zombie";
107 const char kZombieTrace[] = "zombie_dealloc_bt";
109 } // namespace mac
110 #endif
112 size_t RegisterChromeCrashKeys() {
113 // The following keys may be chunked by the underlying crash logging system,
114 // but ultimately constitute a single key-value pair.
115 base::debug::CrashKey fixed_keys[] = {
116 { kClientID, kSmallSize },
117 { kChannel, kSmallSize },
118 { kActiveURL, kLargeSize },
119 { kNumSwitches, kSmallSize },
120 { kNumVariations, kSmallSize },
121 { kVariations, kLargeSize },
122 { kNumExtensionsCount, kSmallSize },
123 { kNumberOfViews, kSmallSize },
124 #if !defined(OS_ANDROID)
125 { kGPUVendorID, kSmallSize },
126 { kGPUDeviceID, kSmallSize },
127 #endif
128 { kGPUDriverVersion, kSmallSize },
129 { kGPUPixelShaderVersion, kSmallSize },
130 { kGPUVertexShaderVersion, kSmallSize },
131 #if defined(OS_MACOSX)
132 { kGPUGLVersion, kSmallSize },
133 #elif defined(OS_POSIX)
134 { kGPUVendor, kSmallSize },
135 { kGPURenderer, kSmallSize },
136 #endif
138 // content/:
139 { "ppapi_path", kMediumSize },
140 { "subresource_url", kLargeSize },
141 #if defined(OS_CHROMEOS)
142 { kNumberOfUsers, kSmallSize },
143 #endif
144 #if defined(OS_MACOSX)
145 { mac::kFirstNSException, kMediumSize },
146 { mac::kFirstNSExceptionTrace, kMediumSize },
147 { mac::kLastNSException, kMediumSize },
148 { mac::kLastNSExceptionTrace, kMediumSize },
149 { mac::kNSException, kMediumSize },
150 { mac::kNSExceptionTrace, kMediumSize },
151 { mac::kSendAction, kMediumSize },
152 { mac::kZombie, kMediumSize },
153 { mac::kZombieTrace, kMediumSize },
154 // content/:
155 { "channel_error_bt", kMediumSize },
156 { "remove_route_bt", kMediumSize },
157 { "rwhvm_window", kMediumSize },
158 // media/:
159 { "VideoCaptureDeviceQTKit", kSmallSize },
160 #endif
163 // This dynamic set of keys is used for sets of key value pairs when gathering
164 // a collection of data, like command line switches or extension IDs.
165 std::vector<base::debug::CrashKey> keys(
166 fixed_keys, fixed_keys + arraysize(fixed_keys));
168 // Register the switches.
170 // The fixed_keys names are string constants. Use static storage for
171 // formatted key names as well, since they will persist for the duration of
172 // the program.
173 static char formatted_keys[kSwitchesMaxCount][sizeof(kSwitch) + 1] =
174 {{ 0 }};
175 const size_t formatted_key_len = sizeof(formatted_keys[0]);
176 for (size_t i = 0; i < kSwitchesMaxCount; ++i) {
177 // Name the keys using 1-based indexing.
178 int n = base::snprintf(
179 formatted_keys[i], formatted_key_len, kSwitch, i + 1);
180 DCHECK_GT(n, 0);
181 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
182 keys.push_back(crash_key);
186 // Register the extension IDs.
188 static char formatted_keys[kExtensionIDMaxCount][sizeof(kExtensionID) + 1] =
189 {{ 0 }};
190 const size_t formatted_key_len = sizeof(formatted_keys[0]);
191 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
192 int n = base::snprintf(
193 formatted_keys[i], formatted_key_len, kExtensionID, i);
194 DCHECK_GT(n, 0);
195 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
196 keys.push_back(crash_key);
200 // Register the printer info.
202 static char formatted_keys[kPrinterInfoCount][sizeof(kPrinterInfo) + 1] =
203 {{ 0 }};
204 const size_t formatted_key_len = sizeof(formatted_keys[0]);
205 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
206 // Key names are 1-indexed.
207 int n = base::snprintf(
208 formatted_keys[i], formatted_key_len, kPrinterInfo, i + 1);
209 DCHECK_GT(n, 0);
210 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
211 keys.push_back(crash_key);
215 return base::debug::InitCrashKeys(&keys.at(0), keys.size(),
216 kSingleChunkLength);
219 void SetClientID(const std::string& client_id) {
220 std::string guid(client_id);
221 // Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY.
222 ReplaceSubstringsAfterOffset(&guid, 0, "-", "");
223 if (guid.empty())
224 return;
226 base::debug::SetCrashKeyValue(kClientID, guid);
227 GoogleUpdateSettings::SetMetricsId(guid);
230 static bool IsBoringSwitch(const std::string& flag) {
231 #if defined(OS_WIN)
232 return StartsWithASCII(flag, "--channel=", true) ||
234 // No point to including this since we already have a ptype field.
235 StartsWithASCII(flag, "--type=", true) ||
237 // Not particularly interesting
238 StartsWithASCII(flag, "--flash-broker=", true) ||
240 // Just about everything has this, don't bother.
241 StartsWithASCII(flag, "/prefetch:", true) ||
243 // We handle the plugin path separately since it is usually too big
244 // to fit in the switches (limited to 63 characters).
245 StartsWithASCII(flag, "--plugin-path=", true) ||
247 // This is too big so we end up truncating it anyway.
248 StartsWithASCII(flag, "--force-fieldtrials=", true) ||
250 // These surround the flags that were added by about:flags, it lets
251 // you distinguish which flags were added manually via the command
252 // line versus those added through about:flags. For the most part
253 // we don't care how an option was enabled, so we strip these.
254 // (If you need to know can always look at the PEB).
255 flag == "--flag-switches-begin" ||
256 flag == "--flag-switches-end";
257 #else
258 return false;
259 #endif
262 void SetSwitchesFromCommandLine(const CommandLine* command_line) {
263 DCHECK(command_line);
264 if (!command_line)
265 return;
267 const CommandLine::StringVector& argv = command_line->argv();
269 // Set the number of switches in case size > kNumSwitches.
270 base::debug::SetCrashKeyValue(kNumSwitches,
271 base::StringPrintf("%" PRIuS, argv.size() - 1));
273 size_t key_i = 1; // Key names are 1-indexed.
275 // Go through the argv, skipping the exec path.
276 for (size_t i = 1; i < argv.size(); ++i) {
277 #if defined(OS_WIN)
278 std::string switch_str = base::WideToUTF8(argv[i]);
279 #else
280 std::string switch_str = argv[i];
281 #endif
283 // Skip uninteresting switches.
284 if (IsBoringSwitch(switch_str))
285 continue;
287 // Stop if there are too many switches.
288 if (i > crash_keys::kSwitchesMaxCount)
289 break;
291 std::string key = base::StringPrintf(kSwitch, key_i++);
292 base::debug::SetCrashKeyValue(key, switch_str);
295 // Clear any remaining switches.
296 for (; key_i <= kSwitchesMaxCount; ++key_i) {
297 base::debug::ClearCrashKey(base::StringPrintf(kSwitch, key_i));
301 void SetVariationsList(const std::vector<std::string>& variations) {
302 base::debug::SetCrashKeyValue(kNumVariations,
303 base::StringPrintf("%" PRIuS, variations.size()));
305 std::string variations_string;
306 variations_string.reserve(kLargeSize);
308 for (size_t i = 0; i < variations.size(); ++i) {
309 const std::string& variation = variations[i];
310 // Do not truncate an individual experiment.
311 if (variations_string.size() + variation.size() >= kLargeSize)
312 break;
313 variations_string += variation;
314 variations_string += ",";
317 base::debug::SetCrashKeyValue(kVariations, variations_string);
320 void SetActiveExtensions(const std::set<std::string>& extensions) {
321 base::debug::SetCrashKeyValue(kNumExtensionsCount,
322 base::StringPrintf("%" PRIuS, extensions.size()));
324 std::set<std::string>::const_iterator it = extensions.begin();
325 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
326 std::string key = base::StringPrintf(kExtensionID, i);
327 if (it == extensions.end()) {
328 base::debug::ClearCrashKey(key);
329 } else {
330 base::debug::SetCrashKeyValue(key, *it);
331 ++it;
336 ScopedPrinterInfo::ScopedPrinterInfo(const base::StringPiece& data) {
337 std::vector<std::string> info;
338 base::SplitString(data.as_string(), ';', &info);
339 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
340 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
341 std::string value;
342 if (i < info.size())
343 value = info[i];
344 base::debug::SetCrashKeyValue(key, value);
348 ScopedPrinterInfo::~ScopedPrinterInfo() {
349 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
350 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
351 base::debug::ClearCrashKey(key);
355 } // namespace crash_keys