1 // Copyright 2014 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 "components/crash/content/app/crash_keys_win.h"
9 #include "base/base_switches.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "components/crash/content/app/crash_reporter_client.h"
19 using crash_reporter::CrashReporterClient
;
23 const size_t kMaxPluginPathLength
= 256;
24 const size_t kMaxDynamicEntries
= 256;
28 CrashKeysWin
* CrashKeysWin::keeper_
;
30 CrashKeysWin::CrashKeysWin() : dynamic_keys_offset_(0) {
31 DCHECK_EQ(static_cast<CrashKeysWin
*>(NULL
), keeper_
);
35 CrashKeysWin::~CrashKeysWin() {
36 DCHECK_EQ(this, keeper_
);
40 // Appends the plugin path to |g_custom_entries|.
41 void CrashKeysWin::SetPluginPath(const std::wstring
& path
) {
42 if (path
.size() > kMaxPluginPathLength
) {
43 // If the path is too long, truncate from the start rather than the end,
44 // since we want to be able to recover the DLL name.
45 SetPluginPath(path
.substr(path
.size() - kMaxPluginPathLength
));
49 // The chunk size without terminator.
50 const size_t kChunkSize
= static_cast<size_t>(
51 google_breakpad::CustomInfoEntry::kValueMaxLength
- 1);
54 size_t chunk_start
= 0; // Current position inside |path|
56 for (chunk_start
= 0; chunk_start
< path
.size(); chunk_index
++) {
57 size_t chunk_length
= std::min(kChunkSize
, path
.size() - chunk_start
);
59 custom_entries_
.push_back(google_breakpad::CustomInfoEntry(
60 base::StringPrintf(L
"plugin-path-chunk-%i", chunk_index
+ 1).c_str(),
61 path
.substr(chunk_start
, chunk_length
).c_str()));
63 chunk_start
+= chunk_length
;
67 // Appends the breakpad dump path to |g_custom_entries|.
68 void CrashKeysWin::SetBreakpadDumpPath(CrashReporterClient
* crash_client
) {
69 base::FilePath crash_dumps_dir_path
;
70 if (crash_client
->GetAlternativeCrashDumpLocation(&crash_dumps_dir_path
)) {
71 custom_entries_
.push_back(google_breakpad::CustomInfoEntry(
72 L
"breakpad-dump-location", crash_dumps_dir_path
.value().c_str()));
76 // Returns the custom info structure based on the dll in parameter and the
78 google_breakpad::CustomClientInfo
*
79 CrashKeysWin::GetCustomInfo(const std::wstring
& exe_path
,
80 const std::wstring
& type
,
81 const std::wstring
& profile_type
,
82 base::CommandLine
* cmd_line
,
83 CrashReporterClient
* crash_client
) {
84 base::string16 version
, product
;
85 base::string16 special_build
;
86 base::string16 channel_name
;
88 crash_client
->GetProductNameAndVersion(
89 base::FilePath(exe_path
),
95 // We only expect this method to be called once per process.
97 custom_entries_
.push_back(
98 google_breakpad::CustomInfoEntry(L
"ver", version
.c_str()));
99 custom_entries_
.push_back(
100 google_breakpad::CustomInfoEntry(L
"prod", product
.c_str()));
101 custom_entries_
.push_back(
102 google_breakpad::CustomInfoEntry(L
"plat", L
"Win32"));
103 custom_entries_
.push_back(
104 google_breakpad::CustomInfoEntry(L
"ptype", type
.c_str()));
105 custom_entries_
.push_back(
106 google_breakpad::CustomInfoEntry(
107 L
"pid", base::IntToString16(::GetCurrentProcessId()).c_str()));
108 custom_entries_
.push_back(
109 google_breakpad::CustomInfoEntry(L
"channel", channel_name
.c_str()));
110 custom_entries_
.push_back(
111 google_breakpad::CustomInfoEntry(L
"profile-type", profile_type
.c_str()));
113 if (!special_build
.empty()) {
114 custom_entries_
.push_back(
115 google_breakpad::CustomInfoEntry(L
"special", special_build
.c_str()));
118 if (type
== L
"plugin" || type
== L
"ppapi") {
119 std::wstring plugin_path
= cmd_line
->GetSwitchValueNative("plugin-path");
120 if (!plugin_path
.empty())
121 SetPluginPath(plugin_path
);
124 // Check whether configuration management controls crash reporting.
125 bool crash_reporting_enabled
= true;
126 bool controlled_by_policy
= crash_client
->ReportingIsEnforcedByPolicy(
127 &crash_reporting_enabled
);
128 bool use_crash_service
= !controlled_by_policy
&&
129 (cmd_line
->HasSwitch(switches::kNoErrorDialogs
) ||
130 crash_client
->IsRunningUnattended());
131 if (use_crash_service
)
132 SetBreakpadDumpPath(crash_client
);
134 // Create space for dynamic ad-hoc keys. The names and values are set using
135 // the API defined in base/debug/crash_logging.h.
136 dynamic_keys_offset_
= custom_entries_
.size();
137 for (size_t i
= 0; i
< kMaxDynamicEntries
; ++i
) {
138 // The names will be mutated as they are set. Un-numbered since these are
139 // merely placeholders. The name cannot be empty because Breakpad's
140 // HTTPUpload will interpret that as an invalid parameter.
141 custom_entries_
.push_back(
142 google_breakpad::CustomInfoEntry(L
"unspecified-crash-key", L
""));
145 static google_breakpad::CustomClientInfo custom_client_info
;
146 custom_client_info
.entries
= &custom_entries_
.front();
147 custom_client_info
.count
= custom_entries_
.size();
149 return &custom_client_info
;
152 void CrashKeysWin::SetCrashKeyValue(
153 const std::wstring
& key
, const std::wstring
& value
) {
154 // CustomInfoEntry limits the length of key and value. If they exceed
155 // their maximum length the underlying string handling functions raise
156 // an exception and prematurely trigger a crash. Truncate here.
157 std::wstring
safe_key(std::wstring(key
).substr(
158 0, google_breakpad::CustomInfoEntry::kNameMaxLength
- 1));
159 std::wstring
safe_value(std::wstring(value
).substr(
160 0, google_breakpad::CustomInfoEntry::kValueMaxLength
- 1));
162 // If we already have a value for this key, update it; otherwise, insert
163 // the new value if we have not exhausted the pre-allocated slots for dynamic
165 base::AutoLock
lock(lock_
);
167 DynamicEntriesMap::iterator it
= dynamic_entries_
.find(safe_key
);
168 google_breakpad::CustomInfoEntry
* entry
= NULL
;
169 if (it
== dynamic_entries_
.end()) {
170 if (dynamic_entries_
.size() >= kMaxDynamicEntries
)
172 entry
= &custom_entries_
[dynamic_keys_offset_
++];
173 dynamic_entries_
.insert(std::make_pair(safe_key
, entry
));
178 entry
->set(safe_key
.data(), safe_value
.data());
181 void CrashKeysWin::ClearCrashKeyValue(const std::wstring
& key
) {
182 base::AutoLock
lock(lock_
);
184 std::wstring
key_string(key
);
185 DynamicEntriesMap::iterator it
= dynamic_entries_
.find(key_string
);
186 if (it
== dynamic_entries_
.end())
189 it
->second
->set_value(NULL
);
192 } // namespace breakpad