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/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/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/crash/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",
99 base::UTF16ToWide(version
).c_str()));
100 custom_entries_
.push_back(
101 google_breakpad::CustomInfoEntry(L
"prod",
102 base::UTF16ToWide(product
).c_str()));
103 custom_entries_
.push_back(
104 google_breakpad::CustomInfoEntry(L
"plat", L
"Win32"));
105 custom_entries_
.push_back(
106 google_breakpad::CustomInfoEntry(L
"ptype", type
.c_str()));
107 custom_entries_
.push_back(google_breakpad::CustomInfoEntry(
108 L
"pid", base::StringPrintf(L
"%d", ::GetCurrentProcessId()).c_str()));
109 custom_entries_
.push_back(google_breakpad::CustomInfoEntry(
110 L
"channel", base::UTF16ToWide(channel_name
).c_str()));
111 custom_entries_
.push_back(google_breakpad::CustomInfoEntry(
112 L
"profile-type", profile_type
.c_str()));
114 if (!special_build
.empty())
115 custom_entries_
.push_back(google_breakpad::CustomInfoEntry(
116 L
"special", base::UTF16ToWide(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
);
125 // Check whether configuration management controls crash reporting.
126 bool crash_reporting_enabled
= true;
127 bool controlled_by_policy
= crash_client
->ReportingIsEnforcedByPolicy(
128 &crash_reporting_enabled
);
129 bool use_crash_service
= !controlled_by_policy
&&
130 (cmd_line
->HasSwitch(switches::kNoErrorDialogs
) ||
131 crash_client
->IsRunningUnattended());
132 if (use_crash_service
)
133 SetBreakpadDumpPath(crash_client
);
135 // Create space for dynamic ad-hoc keys. The names and values are set using
136 // the API defined in base/debug/crash_logging.h.
137 dynamic_keys_offset_
= custom_entries_
.size();
138 for (size_t i
= 0; i
< kMaxDynamicEntries
; ++i
) {
139 // The names will be mutated as they are set. Un-numbered since these are
140 // merely placeholders. The name cannot be empty because Breakpad's
141 // HTTPUpload will interpret that as an invalid parameter.
142 custom_entries_
.push_back(
143 google_breakpad::CustomInfoEntry(L
"unspecified-crash-key", L
""));
146 static google_breakpad::CustomClientInfo custom_client_info
;
147 custom_client_info
.entries
= &custom_entries_
.front();
148 custom_client_info
.count
= custom_entries_
.size();
150 return &custom_client_info
;
153 void CrashKeysWin::SetCrashKeyValue(
154 const std::wstring
& key
, const std::wstring
& value
) {
155 // CustomInfoEntry limits the length of key and value. If they exceed
156 // their maximum length the underlying string handling functions raise
157 // an exception and prematurely trigger a crash. Truncate here.
158 std::wstring
safe_key(std::wstring(key
).substr(
159 0, google_breakpad::CustomInfoEntry::kNameMaxLength
- 1));
160 std::wstring
safe_value(std::wstring(value
).substr(
161 0, google_breakpad::CustomInfoEntry::kValueMaxLength
- 1));
163 // If we already have a value for this key, update it; otherwise, insert
164 // the new value if we have not exhausted the pre-allocated slots for dynamic
166 base::AutoLock
lock(lock_
);
168 DynamicEntriesMap::iterator it
= dynamic_entries_
.find(safe_key
);
169 google_breakpad::CustomInfoEntry
* entry
= NULL
;
170 if (it
== dynamic_entries_
.end()) {
171 if (dynamic_entries_
.size() >= kMaxDynamicEntries
)
173 entry
= &custom_entries_
[dynamic_keys_offset_
++];
174 dynamic_entries_
.insert(std::make_pair(safe_key
, entry
));
179 entry
->set(safe_key
.data(), safe_value
.data());
182 void CrashKeysWin::ClearCrashKeyValue(const std::wstring
& key
) {
183 base::AutoLock
lock(lock_
);
185 std::wstring
key_string(key
);
186 DynamicEntriesMap::iterator it
= dynamic_entries_
.find(key_string
);
187 if (it
== dynamic_entries_
.end())
190 it
->second
->set_value(NULL
);
193 } // namespace breakpad