OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/browser_watcher/postmortem_report_collector.h" | 5 #include "components/browser_watcher/postmortem_report_collector.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/debug/activity_analyzer.h" | 9 #include "base/debug/activity_analyzer.h" |
10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 #include "base/path_service.h" | 14 #include "base/path_service.h" |
15 #include "base/strings/string_piece.h" | |
15 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
16 #include "components/browser_watcher/postmortem_minidump_writer.h" | 17 #include "components/browser_watcher/postmortem_minidump_writer.h" |
17 #include "third_party/crashpad/crashpad/client/settings.h" | 18 #include "third_party/crashpad/crashpad/client/settings.h" |
18 #include "third_party/crashpad/crashpad/util/misc/uuid.h" | 19 #include "third_party/crashpad/crashpad/util/misc/uuid.h" |
19 | 20 |
20 using base::FilePath; | 21 using base::FilePath; |
21 | 22 |
22 namespace browser_watcher { | 23 namespace browser_watcher { |
23 | 24 |
24 using ActivitySnapshot = base::debug::ThreadActivityAnalyzer::Snapshot; | 25 using ActivitySnapshot = base::debug::ThreadActivityAnalyzer::Snapshot; |
26 using base::debug::ActivityUserData; | |
25 using base::debug::GlobalActivityAnalyzer; | 27 using base::debug::GlobalActivityAnalyzer; |
26 using base::debug::ThreadActivityAnalyzer; | 28 using base::debug::ThreadActivityAnalyzer; |
27 using crashpad::CrashReportDatabase; | 29 using crashpad::CrashReportDatabase; |
28 | 30 |
31 namespace { | |
32 | |
33 // Collects stability user data from the recorded format to the collected | |
34 // format. | |
35 void CollectUserData( | |
36 const ActivityUserData::Snapshot& recorded_map, | |
37 google::protobuf::Map<std::string, TypedValue>* collected_map) { | |
38 DCHECK(collected_map); | |
39 | |
40 for (const auto& name_and_value : recorded_map) { | |
41 const ActivityUserData::TypedValue& recorded_value = name_and_value.second; | |
42 TypedValue collected_value; | |
43 | |
44 switch (recorded_value.get_type()) { | |
45 case ActivityUserData::END_OF_VALUES: | |
46 NOTREACHED(); | |
47 break; | |
48 case ActivityUserData::RAW_VALUE: | |
49 collected_value.set_bytes_value(recorded_value.Get().as_string()); | |
50 break; | |
51 case ActivityUserData::RAW_VALUE_REFERENCE: { | |
52 base::StringPiece recorded_ref = recorded_value.GetReference(); | |
53 TypedValue::Reference* collected_ref = | |
54 collected_value.mutable_bytes_reference(); | |
55 collected_ref->set_address( | |
56 reinterpret_cast<uintptr_t>(recorded_ref.data())); | |
57 collected_ref->set_size(recorded_ref.size()); | |
58 break; | |
bcwhite
2016/12/22 17:21:58
I believe style is
} break;
At least, "git cl fo
manzagop (departed)
2017/01/10 14:11:22
The example from the style guide has it inside. Ma
bcwhite
2017/01/10 18:00:38
Acknowledged.
| |
59 } | |
60 case ActivityUserData::STRING_VALUE: | |
61 collected_value.set_string_value( | |
62 recorded_value.GetString().as_string()); | |
63 break; | |
64 case ActivityUserData::STRING_VALUE_REFERENCE: { | |
65 base::StringPiece recorded_ref = recorded_value.GetStringReference(); | |
66 TypedValue::Reference* collected_ref = | |
67 collected_value.mutable_string_reference(); | |
68 collected_ref->set_address( | |
69 reinterpret_cast<uintptr_t>(recorded_ref.data())); | |
70 collected_ref->set_size(recorded_ref.size()); | |
71 break; | |
72 } | |
73 case ActivityUserData::CHAR_VALUE: | |
74 collected_value.set_char_value( | |
75 std::string(1, recorded_value.GetChar())); | |
76 break; | |
77 case ActivityUserData::BOOL_VALUE: | |
78 collected_value.set_bool_value(recorded_value.GetBool()); | |
79 break; | |
80 case ActivityUserData::SIGNED_VALUE: | |
81 collected_value.set_signed_value(recorded_value.GetInt()); | |
82 break; | |
83 case ActivityUserData::UNSIGNED_VALUE: | |
84 collected_value.set_unsigned_value(recorded_value.GetUint()); | |
85 break; | |
86 } | |
87 | |
88 (*collected_map)[name_and_value.first] = collected_value; | |
bcwhite
2016/12/22 17:21:58
This will create an default value and then assign
manzagop (departed)
2017/01/10 14:11:22
I don't think protos can be moved. I've switched t
| |
89 } | |
90 } | |
91 | |
92 } // namespace | |
93 | |
29 PostmortemReportCollector::PostmortemReportCollector( | 94 PostmortemReportCollector::PostmortemReportCollector( |
30 const std::string& product_name, | 95 const std::string& product_name, |
31 const std::string& version_number, | 96 const std::string& version_number, |
32 const std::string& channel_name) | 97 const std::string& channel_name) |
33 : product_name_(product_name), | 98 : product_name_(product_name), |
34 version_number_(version_number), | 99 version_number_(version_number), |
35 channel_name_(channel_name) {} | 100 channel_name_(channel_name) {} |
36 | 101 |
37 int PostmortemReportCollector::CollectAndSubmitForUpload( | 102 int PostmortemReportCollector::CollectAndSubmitForUpload( |
38 const base::FilePath& debug_info_dir, | 103 const base::FilePath& debug_info_dir, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 report->reset(); | 227 report->reset(); |
163 | 228 |
164 // Create a global analyzer. | 229 // Create a global analyzer. |
165 std::unique_ptr<GlobalActivityAnalyzer> global_analyzer = | 230 std::unique_ptr<GlobalActivityAnalyzer> global_analyzer = |
166 GlobalActivityAnalyzer::CreateWithFile(debug_state_file); | 231 GlobalActivityAnalyzer::CreateWithFile(debug_state_file); |
167 if (!global_analyzer) | 232 if (!global_analyzer) |
168 return ANALYZER_CREATION_FAILED; | 233 return ANALYZER_CREATION_FAILED; |
169 | 234 |
170 // Early exit if there is no data. | 235 // Early exit if there is no data. |
171 std::vector<std::string> log_messages = global_analyzer->GetLogMessages(); | 236 std::vector<std::string> log_messages = global_analyzer->GetLogMessages(); |
237 ActivityUserData::Snapshot global_data_snapshot = | |
238 global_analyzer->GetGlobalUserDataSnapshot(); | |
172 ThreadActivityAnalyzer* thread_analyzer = global_analyzer->GetFirstAnalyzer(); | 239 ThreadActivityAnalyzer* thread_analyzer = global_analyzer->GetFirstAnalyzer(); |
173 if (log_messages.empty() && !thread_analyzer) { | 240 if (log_messages.empty() && global_data_snapshot.empty() && |
241 !thread_analyzer) { | |
174 return DEBUG_FILE_NO_DATA; | 242 return DEBUG_FILE_NO_DATA; |
175 } | 243 } |
176 | 244 |
177 // Create the report, then flesh it out. | 245 // Create the report, then flesh it out. |
178 report->reset(new StabilityReport()); | 246 report->reset(new StabilityReport()); |
179 | 247 |
180 // Collect log messages. | 248 // Collect log messages. |
181 for (const std::string& message : log_messages) { | 249 for (const std::string& message : log_messages) { |
182 (*report)->add_log_messages(message); | 250 (*report)->add_log_messages(message); |
183 } | 251 } |
184 | 252 |
253 // Collect global user data. | |
254 CollectUserData(global_data_snapshot, (*report)->mutable_global_data()); | |
255 | |
185 // Collect thread activity data. | 256 // Collect thread activity data. |
186 // Note: a single process is instrumented. | 257 // Note: a single process is instrumented. |
187 ProcessState* process_state = (*report)->add_process_states(); | 258 ProcessState* process_state = (*report)->add_process_states(); |
188 for (; thread_analyzer != nullptr; | 259 for (; thread_analyzer != nullptr; |
189 thread_analyzer = global_analyzer->GetNextAnalyzer()) { | 260 thread_analyzer = global_analyzer->GetNextAnalyzer()) { |
190 // Only valid analyzers are expected per contract of GetFirstAnalyzer / | 261 // Only valid analyzers are expected per contract of GetFirstAnalyzer / |
191 // GetNextAnalyzer. | 262 // GetNextAnalyzer. |
192 DCHECK(thread_analyzer->IsValid()); | 263 DCHECK(thread_analyzer->IsValid()); |
193 | 264 |
194 if (!process_state->has_process_id()) { | 265 if (!process_state->has_process_id()) { |
(...skipping 12 matching lines...) Expand all Loading... | |
207 | 278 |
208 void PostmortemReportCollector::CollectThread( | 279 void PostmortemReportCollector::CollectThread( |
209 const base::debug::ThreadActivityAnalyzer::Snapshot& snapshot, | 280 const base::debug::ThreadActivityAnalyzer::Snapshot& snapshot, |
210 ThreadState* thread_state) { | 281 ThreadState* thread_state) { |
211 DCHECK(thread_state); | 282 DCHECK(thread_state); |
212 | 283 |
213 thread_state->set_thread_name(snapshot.thread_name); | 284 thread_state->set_thread_name(snapshot.thread_name); |
214 thread_state->set_thread_id(snapshot.thread_id); | 285 thread_state->set_thread_id(snapshot.thread_id); |
215 thread_state->set_activity_count(snapshot.activity_stack_depth); | 286 thread_state->set_activity_count(snapshot.activity_stack_depth); |
216 | 287 |
217 for (const base::debug::Activity& recorded : snapshot.activity_stack) { | 288 for (size_t i = 0; i < snapshot.activity_stack.size(); ++i) { |
289 const base::debug::Activity& recorded = snapshot.activity_stack[i]; | |
218 Activity* collected = thread_state->add_activities(); | 290 Activity* collected = thread_state->add_activities(); |
291 | |
292 // Collect activity | |
219 switch (recorded.activity_type) { | 293 switch (recorded.activity_type) { |
220 case base::debug::Activity::ACT_TASK_RUN: | 294 case base::debug::Activity::ACT_TASK_RUN: |
221 collected->set_type(Activity::ACT_TASK_RUN); | 295 collected->set_type(Activity::ACT_TASK_RUN); |
222 collected->set_origin_address(recorded.origin_address); | 296 collected->set_origin_address(recorded.origin_address); |
223 collected->set_task_sequence_id(recorded.data.task.sequence_id); | 297 collected->set_task_sequence_id(recorded.data.task.sequence_id); |
224 break; | 298 break; |
225 case base::debug::Activity::ACT_LOCK_ACQUIRE: | 299 case base::debug::Activity::ACT_LOCK_ACQUIRE: |
226 collected->set_type(Activity::ACT_LOCK_ACQUIRE); | 300 collected->set_type(Activity::ACT_LOCK_ACQUIRE); |
227 collected->set_lock_address(recorded.data.lock.lock_address); | 301 collected->set_lock_address(recorded.data.lock.lock_address); |
228 break; | 302 break; |
229 case base::debug::Activity::ACT_EVENT_WAIT: | 303 case base::debug::Activity::ACT_EVENT_WAIT: |
230 collected->set_type(Activity::ACT_EVENT_WAIT); | 304 collected->set_type(Activity::ACT_EVENT_WAIT); |
231 collected->set_event_address(recorded.data.event.event_address); | 305 collected->set_event_address(recorded.data.event.event_address); |
232 break; | 306 break; |
233 case base::debug::Activity::ACT_THREAD_JOIN: | 307 case base::debug::Activity::ACT_THREAD_JOIN: |
234 collected->set_type(Activity::ACT_THREAD_JOIN); | 308 collected->set_type(Activity::ACT_THREAD_JOIN); |
235 collected->set_thread_id(recorded.data.thread.thread_id); | 309 collected->set_thread_id(recorded.data.thread.thread_id); |
236 break; | 310 break; |
237 case base::debug::Activity::ACT_PROCESS_WAIT: | 311 case base::debug::Activity::ACT_PROCESS_WAIT: |
238 collected->set_type(Activity::ACT_PROCESS_WAIT); | 312 collected->set_type(Activity::ACT_PROCESS_WAIT); |
239 collected->set_process_id(recorded.data.process.process_id); | 313 collected->set_process_id(recorded.data.process.process_id); |
240 break; | 314 break; |
241 default: | 315 default: |
242 break; | 316 break; |
243 } | 317 } |
318 | |
319 // Collect user data | |
320 if (i < snapshot.user_data_stack.size()) { | |
321 CollectUserData(snapshot.user_data_stack[i], | |
322 collected->mutable_user_data()); | |
323 } | |
244 } | 324 } |
245 } | 325 } |
246 | 326 |
247 bool PostmortemReportCollector::WriteReportToMinidump( | 327 bool PostmortemReportCollector::WriteReportToMinidump( |
248 const StabilityReport& report, | 328 const StabilityReport& report, |
249 const crashpad::UUID& client_id, | 329 const crashpad::UUID& client_id, |
250 const crashpad::UUID& report_id, | 330 const crashpad::UUID& report_id, |
251 base::PlatformFile minidump_file) { | 331 base::PlatformFile minidump_file) { |
252 MinidumpInfo minidump_info; | 332 MinidumpInfo minidump_info; |
253 minidump_info.client_id = client_id; | 333 minidump_info.client_id = client_id; |
254 minidump_info.report_id = report_id; | 334 minidump_info.report_id = report_id; |
255 // TODO(manzagop): replace this information, i.e. the reporter's attributes, | 335 // TODO(manzagop): replace this information, i.e. the reporter's attributes, |
256 // by that of the reportee. Doing so requires adding this information to the | 336 // by that of the reportee. Doing so requires adding this information to the |
257 // stability report. In the meantime, there is a tolerable information | 337 // stability report. In the meantime, there is a tolerable information |
258 // mismatch after upgrades. | 338 // mismatch after upgrades. |
259 minidump_info.product_name = product_name(); | 339 minidump_info.product_name = product_name(); |
260 minidump_info.version_number = version_number(); | 340 minidump_info.version_number = version_number(); |
261 minidump_info.channel_name = channel_name(); | 341 minidump_info.channel_name = channel_name(); |
262 #if defined(ARCH_CPU_X86) | 342 #if defined(ARCH_CPU_X86) |
263 minidump_info.platform = std::string("Win32"); | 343 minidump_info.platform = std::string("Win32"); |
264 #elif defined(ARCH_CPU_X86_64) | 344 #elif defined(ARCH_CPU_X86_64) |
265 minidump_info.platform = std::string("Win64"); | 345 minidump_info.platform = std::string("Win64"); |
266 #endif | 346 #endif |
267 | 347 |
268 return WritePostmortemDump(minidump_file, report, minidump_info); | 348 return WritePostmortemDump(minidump_file, report, minidump_info); |
269 } | 349 } |
270 | 350 |
271 } // namespace browser_watcher | 351 } // namespace browser_watcher |
OLD | NEW |