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.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; |
| 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].Swap(&collected_value); |
| 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 |