| 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 |