Revert of Create a new AccountTrackerService (patchset #8 of https://codereview.chrom...
[chromium-blink-merge.git] / chrome / common / crash_keys.cc
bloba7f0091788652a2a5e31ee1b800753f2721487e8
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 COMPILE_ASSERT(kSmallSize <= kSingleChunkLength,
52 crash_key_chunk_size_too_small);
53 #if defined(OS_MACOSX)
54 COMPILE_ASSERT(kMediumSize <= kSingleChunkLength,
55 mac_has_medium_size_crash_key_chunks);
56 #endif
58 const char kClientId[] = "guid";
60 const char kChannel[] = "channel";
62 const char kActiveURL[] = "url-chunk";
64 const char kSwitch[] = "switch-%" PRIuS;
65 const char kNumSwitches[] = "num-switches";
67 const char kNumVariations[] = "num-experiments";
68 const char kVariations[] = "variations";
70 const char kExtensionID[] = "extension-%" PRIuS;
71 const char kNumExtensionsCount[] = "num-extensions";
73 const char kNumberOfViews[] = "num-views";
75 const char kShutdownType[] = "shutdown-type";
77 #if !defined(OS_ANDROID)
78 const char kGPUVendorID[] = "gpu-venid";
79 const char kGPUDeviceID[] = "gpu-devid";
80 #endif
81 const char kGPUDriverVersion[] = "gpu-driver";
82 const char kGPUPixelShaderVersion[] = "gpu-psver";
83 const char kGPUVertexShaderVersion[] = "gpu-vsver";
84 #if defined(OS_MACOSX)
85 const char kGPUGLVersion[] = "gpu-glver";
86 #elif defined(OS_POSIX)
87 const char kGPUVendor[] = "gpu-gl-vendor";
88 const char kGPURenderer[] = "gpu-gl-renderer";
89 #endif
91 const char kPrinterInfo[] = "prn-info-%" PRIuS;
93 #if defined(OS_CHROMEOS)
94 const char kNumberOfUsers[] = "num-users";
95 #endif
97 #if defined(OS_MACOSX)
98 namespace mac {
100 const char kFirstNSException[] = "firstexception";
101 const char kFirstNSExceptionTrace[] = "firstexception_bt";
103 const char kLastNSException[] = "lastexception";
104 const char kLastNSExceptionTrace[] = "lastexception_bt";
106 const char kNSException[] = "nsexception";
107 const char kNSExceptionTrace[] = "nsexception_bt";
109 const char kSendAction[] = "sendaction";
111 const char kZombie[] = "zombie";
112 const char kZombieTrace[] = "zombie_dealloc_bt";
114 } // namespace mac
115 #endif
117 size_t RegisterChromeCrashKeys() {
118 // The following keys may be chunked by the underlying crash logging system,
119 // but ultimately constitute a single key-value pair.
120 base::debug::CrashKey fixed_keys[] = {
121 { kClientId, kSmallSize },
122 { kChannel, kSmallSize },
123 { kActiveURL, kLargeSize },
124 { kNumSwitches, kSmallSize },
125 { kNumVariations, kSmallSize },
126 { kVariations, kLargeSize },
127 { kNumExtensionsCount, kSmallSize },
128 { kNumberOfViews, kSmallSize },
129 { kShutdownType, kSmallSize },
130 #if !defined(OS_ANDROID)
131 { kGPUVendorID, kSmallSize },
132 { kGPUDeviceID, kSmallSize },
133 #endif
134 { kGPUDriverVersion, kSmallSize },
135 { kGPUPixelShaderVersion, kSmallSize },
136 { kGPUVertexShaderVersion, kSmallSize },
137 #if defined(OS_MACOSX)
138 { kGPUGLVersion, kSmallSize },
139 #elif defined(OS_POSIX)
140 { kGPUVendor, kSmallSize },
141 { kGPURenderer, kSmallSize },
142 #endif
144 // base/:
145 { "dm-usage", kSmallSize },
146 // content/:
147 { "ppapi_path", kMediumSize },
148 { "subresource_url", kLargeSize },
149 #if defined(OS_CHROMEOS)
150 { kNumberOfUsers, kSmallSize },
151 #endif
152 #if defined(OS_MACOSX)
153 { mac::kFirstNSException, kMediumSize },
154 { mac::kFirstNSExceptionTrace, kMediumSize },
155 { mac::kLastNSException, kMediumSize },
156 { mac::kLastNSExceptionTrace, kMediumSize },
157 { mac::kNSException, kMediumSize },
158 { mac::kNSExceptionTrace, kMediumSize },
159 { mac::kSendAction, kMediumSize },
160 { mac::kZombie, kMediumSize },
161 { mac::kZombieTrace, kMediumSize },
162 // content/:
163 { "channel_error_bt", kMediumSize },
164 { "remove_route_bt", kMediumSize },
165 { "rwhvm_window", kMediumSize },
166 // The following keys are for diagnosing crashes in http://crbug.com/369661.
167 // They will not be permanent.
168 { "url1", kLargeSize },
169 { "url2", kLargeSize },
170 { "id1", kSmallSize },
171 { "id2", kSmallSize },
172 // End http://crbug.com/369661
173 // media/:
174 { "VideoCaptureDeviceQTKit", kSmallSize },
175 #endif
178 // This dynamic set of keys is used for sets of key value pairs when gathering
179 // a collection of data, like command line switches or extension IDs.
180 std::vector<base::debug::CrashKey> keys(
181 fixed_keys, fixed_keys + arraysize(fixed_keys));
183 // Register the switches.
185 // The fixed_keys names are string constants. Use static storage for
186 // formatted key names as well, since they will persist for the duration of
187 // the program.
188 static char formatted_keys[kSwitchesMaxCount][sizeof(kSwitch) + 1] =
189 {{ 0 }};
190 const size_t formatted_key_len = sizeof(formatted_keys[0]);
191 for (size_t i = 0; i < kSwitchesMaxCount; ++i) {
192 // Name the keys using 1-based indexing.
193 int n = base::snprintf(
194 formatted_keys[i], formatted_key_len, kSwitch, i + 1);
195 DCHECK_GT(n, 0);
196 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
197 keys.push_back(crash_key);
201 // Register the extension IDs.
203 static char formatted_keys[kExtensionIDMaxCount][sizeof(kExtensionID) + 1] =
204 {{ 0 }};
205 const size_t formatted_key_len = sizeof(formatted_keys[0]);
206 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
207 int n = base::snprintf(
208 formatted_keys[i], formatted_key_len, kExtensionID, i + 1);
209 DCHECK_GT(n, 0);
210 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
211 keys.push_back(crash_key);
215 // Register the printer info.
217 static char formatted_keys[kPrinterInfoCount][sizeof(kPrinterInfo) + 1] =
218 {{ 0 }};
219 const size_t formatted_key_len = sizeof(formatted_keys[0]);
220 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
221 // Key names are 1-indexed.
222 int n = base::snprintf(
223 formatted_keys[i], formatted_key_len, kPrinterInfo, i + 1);
224 DCHECK_GT(n, 0);
225 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
226 keys.push_back(crash_key);
230 return base::debug::InitCrashKeys(&keys.at(0), keys.size(),
231 kSingleChunkLength);
234 void SetCrashClientIdFromGUID(const std::string& client_guid) {
235 std::string stripped_guid(client_guid);
236 // Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY.
237 ReplaceSubstringsAfterOffset(&stripped_guid, 0, "-", "");
238 if (stripped_guid.empty())
239 return;
241 base::debug::SetCrashKeyValue(kClientId, stripped_guid);
244 static bool IsBoringSwitch(const std::string& flag) {
245 #if defined(OS_WIN)
246 return StartsWithASCII(flag, "--channel=", true) ||
248 // No point to including this since we already have a ptype field.
249 StartsWithASCII(flag, "--type=", true) ||
251 // Not particularly interesting
252 StartsWithASCII(flag, "--flash-broker=", true) ||
254 // Just about everything has this, don't bother.
255 StartsWithASCII(flag, "/prefetch:", true) ||
257 // We handle the plugin path separately since it is usually too big
258 // to fit in the switches (limited to 63 characters).
259 StartsWithASCII(flag, "--plugin-path=", true) ||
261 // This is too big so we end up truncating it anyway.
262 StartsWithASCII(flag, "--force-fieldtrials=", true) ||
264 // These surround the flags that were added by about:flags, it lets
265 // you distinguish which flags were added manually via the command
266 // line versus those added through about:flags. For the most part
267 // we don't care how an option was enabled, so we strip these.
268 // (If you need to know can always look at the PEB).
269 flag == "--flag-switches-begin" ||
270 flag == "--flag-switches-end";
271 #elif defined(OS_CHROMEOS)
272 static const char* kIgnoreSwitches[] = {
273 ::switches::kEnableImplSidePainting,
274 ::switches::kEnableLogging,
275 ::switches::kFlagSwitchesBegin,
276 ::switches::kFlagSwitchesEnd,
277 ::switches::kLoggingLevel,
278 ::switches::kPpapiFlashArgs,
279 ::switches::kPpapiFlashPath,
280 ::switches::kRegisterPepperPlugins,
281 ::switches::kUIPrioritizeInGpuProcess,
282 ::switches::kUseGL,
283 ::switches::kUserDataDir,
284 ::switches::kV,
285 ::switches::kVModule,
286 // Cros/CC flgas are specified as raw strings to avoid dependency.
287 "ash-default-wallpaper-large",
288 "ash-default-wallpaper-small",
289 "ash-guest-wallpaper-large",
290 "ash-guest-wallpaper-small",
291 "enterprise-enable-forced-re-enrollment",
292 "enterprise-enrollment-initial-modulus",
293 "enterprise-enrollment-modulus-limit",
294 "login-profile",
295 "login-user",
296 "max-tiles-for-interest-area",
297 "max-unused-resource-memory-usage-percentage",
298 "termination-message-file",
299 "use-cras",
301 if (!StartsWithASCII(flag, "--", true))
302 return false;
303 std::size_t end = flag.find("=");
304 int len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
305 for (size_t i = 0; i < arraysize(kIgnoreSwitches); ++i) {
306 if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
307 return true;
309 return false;
310 #else
311 return false;
312 #endif
315 void SetSwitchesFromCommandLine(const CommandLine* command_line) {
316 DCHECK(command_line);
317 if (!command_line)
318 return;
320 const CommandLine::StringVector& argv = command_line->argv();
322 // Set the number of switches in case size > kNumSwitches.
323 base::debug::SetCrashKeyValue(kNumSwitches,
324 base::StringPrintf("%" PRIuS, argv.size() - 1));
326 size_t key_i = 1; // Key names are 1-indexed.
328 // Go through the argv, skipping the exec path.
329 for (size_t i = 1; i < argv.size(); ++i) {
330 #if defined(OS_WIN)
331 std::string switch_str = base::WideToUTF8(argv[i]);
332 #else
333 std::string switch_str = argv[i];
334 #endif
336 // Skip uninteresting switches.
337 if (IsBoringSwitch(switch_str))
338 continue;
340 // Stop if there are too many switches.
341 if (i > crash_keys::kSwitchesMaxCount)
342 break;
344 std::string key = base::StringPrintf(kSwitch, key_i++);
345 base::debug::SetCrashKeyValue(key, switch_str);
348 // Clear any remaining switches.
349 for (; key_i <= kSwitchesMaxCount; ++key_i) {
350 base::debug::ClearCrashKey(base::StringPrintf(kSwitch, key_i));
354 void SetVariationsList(const std::vector<std::string>& variations) {
355 base::debug::SetCrashKeyValue(kNumVariations,
356 base::StringPrintf("%" PRIuS, variations.size()));
358 std::string variations_string;
359 variations_string.reserve(kLargeSize);
361 for (size_t i = 0; i < variations.size(); ++i) {
362 const std::string& variation = variations[i];
363 // Do not truncate an individual experiment.
364 if (variations_string.size() + variation.size() >= kLargeSize)
365 break;
366 variations_string += variation;
367 variations_string += ",";
370 base::debug::SetCrashKeyValue(kVariations, variations_string);
373 void SetActiveExtensions(const std::set<std::string>& extensions) {
374 base::debug::SetCrashKeyValue(kNumExtensionsCount,
375 base::StringPrintf("%" PRIuS, extensions.size()));
377 std::set<std::string>::const_iterator it = extensions.begin();
378 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
379 std::string key = base::StringPrintf(kExtensionID, i + 1);
380 if (it == extensions.end()) {
381 base::debug::ClearCrashKey(key);
382 } else {
383 base::debug::SetCrashKeyValue(key, *it);
384 ++it;
389 ScopedPrinterInfo::ScopedPrinterInfo(const base::StringPiece& data) {
390 std::vector<std::string> info;
391 base::SplitString(data.as_string(), ';', &info);
392 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
393 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
394 std::string value;
395 if (i < info.size())
396 value = info[i];
397 base::debug::SetCrashKeyValue(key, value);
401 ScopedPrinterInfo::~ScopedPrinterInfo() {
402 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
403 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
404 base::debug::ClearCrashKey(key);
408 } // namespace crash_keys