Suppress tabs permission warning if there is already a browsingHistory warning.
[chromium-blink-merge.git] / chrome / common / crash_keys.cc
blob461e9111cd1a8deae0a0f982112e50e81c8ca3e9
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 #elif defined(OS_CHROMEOS)
21 #include "chrome/common/chrome_switches.h"
22 #include "gpu/command_buffer/service/gpu_switches.h"
23 #include "ui/gl/gl_switches.h"
24 #endif
26 namespace crash_keys {
28 // A small crash key, guaranteed to never be split into multiple pieces.
29 const size_t kSmallSize = 63;
31 // A medium crash key, which will be chunked on certain platforms but not
32 // others. Guaranteed to never be more than four chunks.
33 const size_t kMediumSize = kSmallSize * 4;
35 // A large crash key, which will be chunked on all platforms. This should be
36 // used sparingly.
37 const size_t kLargeSize = kSmallSize * 16;
39 // The maximum lengths specified by breakpad include the trailing NULL, so
40 // the actual length of the string is one less.
41 #if defined(OS_MACOSX)
42 static const size_t kSingleChunkLength =
43 google_breakpad::SimpleStringDictionary::value_size - 1;
44 #elif defined(OS_WIN)
45 static const size_t kSingleChunkLength =
46 google_breakpad::CustomInfoEntry::kValueMaxLength - 1;
47 #else
48 static const size_t kSingleChunkLength = 63;
49 #endif
51 // Guarantees for crash key sizes.
52 COMPILE_ASSERT(kSmallSize <= kSingleChunkLength,
53 crash_key_chunk_size_too_small);
54 #if defined(OS_MACOSX)
55 COMPILE_ASSERT(kMediumSize <= kSingleChunkLength,
56 mac_has_medium_size_crash_key_chunks);
57 #endif
59 const char kClientID[] = "guid";
61 const char kChannel[] = "channel";
63 const char kActiveURL[] = "url-chunk";
65 const char kSwitch[] = "switch-%" PRIuS;
66 const char kNumSwitches[] = "num-switches";
68 const char kNumVariations[] = "num-experiments";
69 const char kVariations[] = "variations";
71 const char kExtensionID[] = "extension-%" PRIuS;
72 const char kNumExtensionsCount[] = "num-extensions";
74 const char kNumberOfViews[] = "num-views";
76 const char kShutdownType[] = "shutdown-type";
78 #if !defined(OS_ANDROID)
79 const char kGPUVendorID[] = "gpu-venid";
80 const char kGPUDeviceID[] = "gpu-devid";
81 #endif
82 const char kGPUDriverVersion[] = "gpu-driver";
83 const char kGPUPixelShaderVersion[] = "gpu-psver";
84 const char kGPUVertexShaderVersion[] = "gpu-vsver";
85 #if defined(OS_MACOSX)
86 const char kGPUGLVersion[] = "gpu-glver";
87 #elif defined(OS_POSIX)
88 const char kGPUVendor[] = "gpu-gl-vendor";
89 const char kGPURenderer[] = "gpu-gl-renderer";
90 #endif
92 const char kPrinterInfo[] = "prn-info-%" PRIuS;
94 #if defined(OS_CHROMEOS)
95 const char kNumberOfUsers[] = "num-users";
96 #endif
98 #if defined(OS_MACOSX)
99 namespace mac {
101 const char kFirstNSException[] = "firstexception";
102 const char kFirstNSExceptionTrace[] = "firstexception_bt";
104 const char kLastNSException[] = "lastexception";
105 const char kLastNSExceptionTrace[] = "lastexception_bt";
107 const char kNSException[] = "nsexception";
108 const char kNSExceptionTrace[] = "nsexception_bt";
110 const char kSendAction[] = "sendaction";
112 const char kZombie[] = "zombie";
113 const char kZombieTrace[] = "zombie_dealloc_bt";
115 } // namespace mac
116 #endif
118 size_t RegisterChromeCrashKeys() {
119 // The following keys may be chunked by the underlying crash logging system,
120 // but ultimately constitute a single key-value pair.
121 base::debug::CrashKey fixed_keys[] = {
122 { kClientID, kSmallSize },
123 { kChannel, kSmallSize },
124 { kActiveURL, kLargeSize },
125 { kNumSwitches, kSmallSize },
126 { kNumVariations, kSmallSize },
127 { kVariations, kLargeSize },
128 { kNumExtensionsCount, kSmallSize },
129 { kNumberOfViews, kSmallSize },
130 { kShutdownType, kSmallSize },
131 #if !defined(OS_ANDROID)
132 { kGPUVendorID, kSmallSize },
133 { kGPUDeviceID, kSmallSize },
134 #endif
135 { kGPUDriverVersion, kSmallSize },
136 { kGPUPixelShaderVersion, kSmallSize },
137 { kGPUVertexShaderVersion, kSmallSize },
138 #if defined(OS_MACOSX)
139 { kGPUGLVersion, kSmallSize },
140 #elif defined(OS_POSIX)
141 { kGPUVendor, kSmallSize },
142 { kGPURenderer, kSmallSize },
143 #endif
145 // content/:
146 { "ppapi_path", kMediumSize },
147 { "subresource_url", kLargeSize },
148 #if defined(OS_CHROMEOS)
149 { kNumberOfUsers, kSmallSize },
150 #endif
151 #if defined(OS_MACOSX)
152 { mac::kFirstNSException, kMediumSize },
153 { mac::kFirstNSExceptionTrace, kMediumSize },
154 { mac::kLastNSException, kMediumSize },
155 { mac::kLastNSExceptionTrace, kMediumSize },
156 { mac::kNSException, kMediumSize },
157 { mac::kNSExceptionTrace, kMediumSize },
158 { mac::kSendAction, kMediumSize },
159 { mac::kZombie, kMediumSize },
160 { mac::kZombieTrace, kMediumSize },
161 // content/:
162 { "channel_error_bt", kMediumSize },
163 { "remove_route_bt", kMediumSize },
164 { "rwhvm_window", kMediumSize },
165 // media/:
166 { "VideoCaptureDeviceQTKit", kSmallSize },
167 #endif
170 // This dynamic set of keys is used for sets of key value pairs when gathering
171 // a collection of data, like command line switches or extension IDs.
172 std::vector<base::debug::CrashKey> keys(
173 fixed_keys, fixed_keys + arraysize(fixed_keys));
175 // Register the switches.
177 // The fixed_keys names are string constants. Use static storage for
178 // formatted key names as well, since they will persist for the duration of
179 // the program.
180 static char formatted_keys[kSwitchesMaxCount][sizeof(kSwitch) + 1] =
181 {{ 0 }};
182 const size_t formatted_key_len = sizeof(formatted_keys[0]);
183 for (size_t i = 0; i < kSwitchesMaxCount; ++i) {
184 // Name the keys using 1-based indexing.
185 int n = base::snprintf(
186 formatted_keys[i], formatted_key_len, kSwitch, i + 1);
187 DCHECK_GT(n, 0);
188 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
189 keys.push_back(crash_key);
193 // Register the extension IDs.
195 static char formatted_keys[kExtensionIDMaxCount][sizeof(kExtensionID) + 1] =
196 {{ 0 }};
197 const size_t formatted_key_len = sizeof(formatted_keys[0]);
198 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
199 int n = base::snprintf(
200 formatted_keys[i], formatted_key_len, kExtensionID, i + 1);
201 DCHECK_GT(n, 0);
202 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
203 keys.push_back(crash_key);
207 // Register the printer info.
209 static char formatted_keys[kPrinterInfoCount][sizeof(kPrinterInfo) + 1] =
210 {{ 0 }};
211 const size_t formatted_key_len = sizeof(formatted_keys[0]);
212 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
213 // Key names are 1-indexed.
214 int n = base::snprintf(
215 formatted_keys[i], formatted_key_len, kPrinterInfo, i + 1);
216 DCHECK_GT(n, 0);
217 base::debug::CrashKey crash_key = { formatted_keys[i], kSmallSize };
218 keys.push_back(crash_key);
222 return base::debug::InitCrashKeys(&keys.at(0), keys.size(),
223 kSingleChunkLength);
226 void SetClientID(const std::string& client_id) {
227 std::string guid(client_id);
228 // Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY.
229 ReplaceSubstringsAfterOffset(&guid, 0, "-", "");
230 if (guid.empty())
231 return;
233 base::debug::SetCrashKeyValue(kClientID, guid);
234 GoogleUpdateSettings::SetMetricsId(guid);
237 static bool IsBoringSwitch(const std::string& flag) {
238 #if defined(OS_WIN)
239 return StartsWithASCII(flag, "--channel=", true) ||
241 // No point to including this since we already have a ptype field.
242 StartsWithASCII(flag, "--type=", true) ||
244 // Not particularly interesting
245 StartsWithASCII(flag, "--flash-broker=", true) ||
247 // Just about everything has this, don't bother.
248 StartsWithASCII(flag, "/prefetch:", true) ||
250 // We handle the plugin path separately since it is usually too big
251 // to fit in the switches (limited to 63 characters).
252 StartsWithASCII(flag, "--plugin-path=", true) ||
254 // This is too big so we end up truncating it anyway.
255 StartsWithASCII(flag, "--force-fieldtrials=", true) ||
257 // These surround the flags that were added by about:flags, it lets
258 // you distinguish which flags were added manually via the command
259 // line versus those added through about:flags. For the most part
260 // we don't care how an option was enabled, so we strip these.
261 // (If you need to know can always look at the PEB).
262 flag == "--flag-switches-begin" ||
263 flag == "--flag-switches-end";
264 #elif defined(OS_CHROMEOS)
265 static const char* kIgnoreSwitches[] = {
266 ::switches::kEnableCompositingForFixedPosition,
267 ::switches::kEnableImplSidePainting,
268 ::switches::kEnableLogging,
269 ::switches::kFlagSwitchesBegin,
270 ::switches::kFlagSwitchesEnd,
271 ::switches::kLoggingLevel,
272 ::switches::kPpapiFlashArgs,
273 ::switches::kPpapiFlashPath,
274 ::switches::kRegisterPepperPlugins,
275 ::switches::kUIPrioritizeInGpuProcess,
276 ::switches::kUseGL,
277 ::switches::kUserDataDir,
278 ::switches::kV,
279 ::switches::kVModule,
280 // Cros/CC flgas are specified as raw strings to avoid dependency.
281 "ash-default-wallpaper-large",
282 "ash-default-wallpaper-small",
283 "ash-guest-wallpaper-large",
284 "ash-guest-wallpaper-small",
285 "enterprise-enable-forced-re-enrollment",
286 "enterprise-enrollment-initial-modulus",
287 "enterprise-enrollment-modulus-limit",
288 "login-profile",
289 "login-user",
290 "max-tiles-for-interest-area",
291 "max-unused-resource-memory-usage-percentage",
292 "termination-message-file",
293 "use-cras",
295 if (!StartsWithASCII(flag, "--", true))
296 return false;
297 std::size_t end = flag.find("=");
298 int len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
299 for (size_t i = 0; i < arraysize(kIgnoreSwitches); ++i) {
300 if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
301 return true;
303 return false;
304 #else
305 return false;
306 #endif
309 void SetSwitchesFromCommandLine(const CommandLine* command_line) {
310 DCHECK(command_line);
311 if (!command_line)
312 return;
314 const CommandLine::StringVector& argv = command_line->argv();
316 // Set the number of switches in case size > kNumSwitches.
317 base::debug::SetCrashKeyValue(kNumSwitches,
318 base::StringPrintf("%" PRIuS, argv.size() - 1));
320 size_t key_i = 1; // Key names are 1-indexed.
322 // Go through the argv, skipping the exec path.
323 for (size_t i = 1; i < argv.size(); ++i) {
324 #if defined(OS_WIN)
325 std::string switch_str = base::WideToUTF8(argv[i]);
326 #else
327 std::string switch_str = argv[i];
328 #endif
330 // Skip uninteresting switches.
331 if (IsBoringSwitch(switch_str))
332 continue;
334 // Stop if there are too many switches.
335 if (i > crash_keys::kSwitchesMaxCount)
336 break;
338 std::string key = base::StringPrintf(kSwitch, key_i++);
339 base::debug::SetCrashKeyValue(key, switch_str);
342 // Clear any remaining switches.
343 for (; key_i <= kSwitchesMaxCount; ++key_i) {
344 base::debug::ClearCrashKey(base::StringPrintf(kSwitch, key_i));
348 void SetVariationsList(const std::vector<std::string>& variations) {
349 base::debug::SetCrashKeyValue(kNumVariations,
350 base::StringPrintf("%" PRIuS, variations.size()));
352 std::string variations_string;
353 variations_string.reserve(kLargeSize);
355 for (size_t i = 0; i < variations.size(); ++i) {
356 const std::string& variation = variations[i];
357 // Do not truncate an individual experiment.
358 if (variations_string.size() + variation.size() >= kLargeSize)
359 break;
360 variations_string += variation;
361 variations_string += ",";
364 base::debug::SetCrashKeyValue(kVariations, variations_string);
367 void SetActiveExtensions(const std::set<std::string>& extensions) {
368 base::debug::SetCrashKeyValue(kNumExtensionsCount,
369 base::StringPrintf("%" PRIuS, extensions.size()));
371 std::set<std::string>::const_iterator it = extensions.begin();
372 for (size_t i = 0; i < kExtensionIDMaxCount; ++i) {
373 std::string key = base::StringPrintf(kExtensionID, i + 1);
374 if (it == extensions.end()) {
375 base::debug::ClearCrashKey(key);
376 } else {
377 base::debug::SetCrashKeyValue(key, *it);
378 ++it;
383 ScopedPrinterInfo::ScopedPrinterInfo(const base::StringPiece& data) {
384 std::vector<std::string> info;
385 base::SplitString(data.as_string(), ';', &info);
386 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
387 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
388 std::string value;
389 if (i < info.size())
390 value = info[i];
391 base::debug::SetCrashKeyValue(key, value);
395 ScopedPrinterInfo::~ScopedPrinterInfo() {
396 for (size_t i = 0; i < kPrinterInfoCount; ++i) {
397 std::string key = base::StringPrintf(kPrinterInfo, i + 1);
398 base::debug::ClearCrashKey(key);
402 } // namespace crash_keys