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 <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <set> | 10 #include <set> |
11 #include <string> | 11 #include <string> |
12 #include <utility> | 12 #include <utility> |
13 #include <vector> | 13 #include <vector> |
14 | 14 |
| 15 #include "base/debug/activity_analyzer.h" |
15 #include "base/debug/activity_tracker.h" | 16 #include "base/debug/activity_tracker.h" |
16 #include "base/files/file.h" | 17 #include "base/files/file.h" |
17 #include "base/files/file_path.h" | 18 #include "base/files/file_path.h" |
18 #include "base/files/file_util.h" | 19 #include "base/files/file_util.h" |
19 #include "base/files/memory_mapped_file.h" | 20 #include "base/files/memory_mapped_file.h" |
20 #include "base/files/scoped_file.h" | 21 #include "base/files/scoped_file.h" |
21 #include "base/files/scoped_temp_dir.h" | 22 #include "base/files/scoped_temp_dir.h" |
22 #include "base/memory/ptr_util.h" | 23 #include "base/memory/ptr_util.h" |
23 #include "base/metrics/persistent_memory_allocator.h" | 24 #include "base/metrics/persistent_memory_allocator.h" |
24 #include "base/process/process_handle.h" | 25 #include "base/process/process_handle.h" |
| 26 #include "base/stl_util.h" |
25 #include "base/threading/platform_thread.h" | 27 #include "base/threading/platform_thread.h" |
26 #include "testing/gmock/include/gmock/gmock.h" | 28 #include "testing/gmock/include/gmock/gmock.h" |
27 #include "testing/gtest/include/gtest/gtest.h" | 29 #include "testing/gtest/include/gtest/gtest.h" |
28 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | 30 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
29 | 31 |
30 namespace browser_watcher { | 32 namespace browser_watcher { |
31 | 33 |
32 using base::debug::ActivityData; | 34 using base::debug::ActivityData; |
| 35 using base::debug::ActivityTrackerMemoryAllocator; |
| 36 using base::debug::ActivityUserData; |
33 using base::debug::GlobalActivityTracker; | 37 using base::debug::GlobalActivityTracker; |
34 using base::debug::ThreadActivityTracker; | 38 using base::debug::ThreadActivityTracker; |
35 using base::File; | 39 using base::File; |
36 using base::FilePersistentMemoryAllocator; | 40 using base::FilePersistentMemoryAllocator; |
37 using base::MemoryMappedFile; | 41 using base::MemoryMappedFile; |
38 using base::PersistentMemoryAllocator; | 42 using base::PersistentMemoryAllocator; |
39 using base::WrapUnique; | 43 using base::WrapUnique; |
40 using crashpad::CrashReportDatabase; | 44 using crashpad::CrashReportDatabase; |
41 using crashpad::Settings; | 45 using crashpad::Settings; |
42 using crashpad::UUID; | 46 using crashpad::UUID; |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 }; | 420 }; |
417 | 421 |
418 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { | 422 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { |
419 // Create some activity data. | 423 // Create some activity data. |
420 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), | 424 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), |
421 base::debug::Activity::ACT_TASK_RUN, | 425 base::debug::Activity::ACT_TASK_RUN, |
422 ActivityData::ForTask(kTaskSequenceNum)); | 426 ActivityData::ForTask(kTaskSequenceNum)); |
423 tracker_->PushActivity( | 427 tracker_->PushActivity( |
424 nullptr, base::debug::Activity::ACT_LOCK_ACQUIRE, | 428 nullptr, base::debug::Activity::ACT_LOCK_ACQUIRE, |
425 ActivityData::ForLock(reinterpret_cast<void*>(kLockAddress))); | 429 ActivityData::ForLock(reinterpret_cast<void*>(kLockAddress))); |
426 tracker_->PushActivity( | 430 ThreadActivityTracker::ActivityId activity_id = tracker_->PushActivity( |
427 nullptr, base::debug::Activity::ACT_EVENT_WAIT, | 431 nullptr, base::debug::Activity::ACT_EVENT_WAIT, |
428 ActivityData::ForEvent(reinterpret_cast<void*>(kEventAddress))); | 432 ActivityData::ForEvent(reinterpret_cast<void*>(kEventAddress))); |
429 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN, | 433 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN, |
430 ActivityData::ForThread(kThreadId)); | 434 ActivityData::ForThread(kThreadId)); |
431 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_PROCESS_WAIT, | 435 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_PROCESS_WAIT, |
432 ActivityData::ForProcess(kProcessId)); | 436 ActivityData::ForProcess(kProcessId)); |
433 // Note: this exceeds the activity stack's capacity. | 437 // Note: this exceeds the activity stack's capacity. |
434 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN, | 438 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN, |
435 ActivityData::ForThread(kAnotherThreadId)); | 439 ActivityData::ForThread(kAnotherThreadId)); |
436 | 440 |
| 441 // Add some user data. |
| 442 ActivityTrackerMemoryAllocator user_data_allocator( |
| 443 allocator_.get(), GlobalActivityTracker::kTypeIdUserDataRecord, |
| 444 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); |
| 445 std::unique_ptr<ActivityUserData> user_data = |
| 446 tracker_->GetUserData(activity_id, &user_data_allocator); |
| 447 user_data->SetInt("some_int", 42); |
| 448 |
437 // Validate collection returns the expected report. | 449 // Validate collection returns the expected report. |
438 PostmortemReportCollector collector(kProductName, kVersionNumber, | 450 PostmortemReportCollector collector(kProductName, kVersionNumber, |
439 kChannelName); | 451 kChannelName); |
440 std::unique_ptr<StabilityReport> report; | 452 std::unique_ptr<StabilityReport> report; |
441 ASSERT_EQ(PostmortemReportCollector::SUCCESS, | 453 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
442 collector.Collect(debug_file_path(), &report)); | 454 collector.Collect(debug_file_path(), &report)); |
443 ASSERT_NE(nullptr, report); | 455 ASSERT_NE(nullptr, report); |
444 | 456 |
445 // Validate the report. | 457 // Validate the report. |
446 ASSERT_EQ(1, report->process_states_size()); | 458 ASSERT_EQ(1, report->process_states_size()); |
(...skipping 10 matching lines...) Expand all Loading... |
457 thread_state.thread_id()); | 469 thread_state.thread_id()); |
458 #endif | 470 #endif |
459 | 471 |
460 EXPECT_EQ(6, thread_state.activity_count()); | 472 EXPECT_EQ(6, thread_state.activity_count()); |
461 ASSERT_EQ(5, thread_state.activities_size()); | 473 ASSERT_EQ(5, thread_state.activities_size()); |
462 { | 474 { |
463 const Activity& activity = thread_state.activities(0); | 475 const Activity& activity = thread_state.activities(0); |
464 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); | 476 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); |
465 EXPECT_EQ(kTaskOrigin, activity.origin_address()); | 477 EXPECT_EQ(kTaskOrigin, activity.origin_address()); |
466 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); | 478 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); |
| 479 EXPECT_EQ(0U, activity.user_data().size()); |
467 } | 480 } |
468 { | 481 { |
469 const Activity& activity = thread_state.activities(1); | 482 const Activity& activity = thread_state.activities(1); |
470 EXPECT_EQ(Activity::ACT_LOCK_ACQUIRE, activity.type()); | 483 EXPECT_EQ(Activity::ACT_LOCK_ACQUIRE, activity.type()); |
471 EXPECT_EQ(kLockAddress, activity.lock_address()); | 484 EXPECT_EQ(kLockAddress, activity.lock_address()); |
| 485 EXPECT_EQ(0U, activity.user_data().size()); |
472 } | 486 } |
473 { | 487 { |
474 const Activity& activity = thread_state.activities(2); | 488 const Activity& activity = thread_state.activities(2); |
475 EXPECT_EQ(Activity::ACT_EVENT_WAIT, activity.type()); | 489 EXPECT_EQ(Activity::ACT_EVENT_WAIT, activity.type()); |
476 EXPECT_EQ(kEventAddress, activity.event_address()); | 490 EXPECT_EQ(kEventAddress, activity.event_address()); |
| 491 ASSERT_EQ(1U, activity.user_data().size()); |
| 492 ASSERT_TRUE(base::ContainsKey(activity.user_data(), "some_int")); |
| 493 EXPECT_EQ(TypedValue::kSignedValue, |
| 494 activity.user_data().at("some_int").value_case()); |
| 495 EXPECT_EQ(42, activity.user_data().at("some_int").signed_value()); |
477 } | 496 } |
478 { | 497 { |
479 const Activity& activity = thread_state.activities(3); | 498 const Activity& activity = thread_state.activities(3); |
480 EXPECT_EQ(Activity::ACT_THREAD_JOIN, activity.type()); | 499 EXPECT_EQ(Activity::ACT_THREAD_JOIN, activity.type()); |
481 EXPECT_EQ(kThreadId, activity.thread_id()); | 500 EXPECT_EQ(kThreadId, activity.thread_id()); |
| 501 EXPECT_EQ(0U, activity.user_data().size()); |
482 } | 502 } |
483 { | 503 { |
484 const Activity& activity = thread_state.activities(4); | 504 const Activity& activity = thread_state.activities(4); |
485 EXPECT_EQ(Activity::ACT_PROCESS_WAIT, activity.type()); | 505 EXPECT_EQ(Activity::ACT_PROCESS_WAIT, activity.type()); |
486 EXPECT_EQ(kProcessId, activity.process_id()); | 506 EXPECT_EQ(kProcessId, activity.process_id()); |
| 507 EXPECT_EQ(0U, activity.user_data().size()); |
487 } | 508 } |
488 } | 509 } |
489 | 510 |
490 class PostmortemReportCollectorCollectionFromGlobalTrackerTest | 511 class PostmortemReportCollectorCollectionFromGlobalTrackerTest |
491 : public testing::Test { | 512 : public testing::Test { |
492 public: | 513 public: |
493 const int kMemorySize = 1 << 20; // 1MiB | 514 const int kMemorySize = 1 << 20; // 1MiB |
494 | 515 |
495 PostmortemReportCollectorCollectionFromGlobalTrackerTest() {} | 516 PostmortemReportCollectorCollectionFromGlobalTrackerTest() {} |
496 ~PostmortemReportCollectorCollectionFromGlobalTrackerTest() override { | 517 ~PostmortemReportCollectorCollectionFromGlobalTrackerTest() override { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 ASSERT_EQ(PostmortemReportCollector::SUCCESS, | 552 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
532 collector.Collect(debug_file_path(), &report)); | 553 collector.Collect(debug_file_path(), &report)); |
533 ASSERT_NE(nullptr, report); | 554 ASSERT_NE(nullptr, report); |
534 | 555 |
535 // Validate the report's log content. | 556 // Validate the report's log content. |
536 ASSERT_EQ(2, report->log_messages_size()); | 557 ASSERT_EQ(2, report->log_messages_size()); |
537 ASSERT_EQ("hello world", report->log_messages(0)); | 558 ASSERT_EQ("hello world", report->log_messages(0)); |
538 ASSERT_EQ("foo bar", report->log_messages(1)); | 559 ASSERT_EQ("foo bar", report->log_messages(1)); |
539 } | 560 } |
540 | 561 |
| 562 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, |
| 563 GlobalUserDataCollection) { |
| 564 const char string1[] = "foo"; |
| 565 const char string2[] = "bar"; |
| 566 |
| 567 // Record some global user data. |
| 568 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, |
| 569 "", 3); |
| 570 ActivityUserData& global_data = GlobalActivityTracker::Get()->user_data(); |
| 571 global_data.Set("raw", "foo", 3); |
| 572 global_data.SetString("string", "bar"); |
| 573 global_data.SetChar("char", '9'); |
| 574 global_data.SetInt("int", -9999); |
| 575 global_data.SetUint("uint", 9999); |
| 576 global_data.SetBool("bool", true); |
| 577 global_data.SetReference("ref", string1, strlen(string1)); |
| 578 global_data.SetStringReference("sref", string2); |
| 579 |
| 580 // Collect the stability report. |
| 581 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 582 kChannelName); |
| 583 std::unique_ptr<StabilityReport> report; |
| 584 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
| 585 collector.Collect(debug_file_path(), &report)); |
| 586 ASSERT_NE(nullptr, report); |
| 587 |
| 588 // Validate the report's log content. |
| 589 const auto& collected_data = report->global_data(); |
| 590 ASSERT_EQ(8U, collected_data.size()); |
| 591 |
| 592 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); |
| 593 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); |
| 594 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); |
| 595 |
| 596 ASSERT_TRUE(base::ContainsKey(collected_data, "string")); |
| 597 EXPECT_EQ(TypedValue::kStringValue, collected_data.at("string").value_case()); |
| 598 EXPECT_EQ("bar", collected_data.at("string").string_value()); |
| 599 |
| 600 ASSERT_TRUE(base::ContainsKey(collected_data, "char")); |
| 601 EXPECT_EQ(TypedValue::kCharValue, collected_data.at("char").value_case()); |
| 602 EXPECT_EQ("9", collected_data.at("char").char_value()); |
| 603 |
| 604 ASSERT_TRUE(base::ContainsKey(collected_data, "int")); |
| 605 EXPECT_EQ(TypedValue::kSignedValue, collected_data.at("int").value_case()); |
| 606 EXPECT_EQ(-9999, collected_data.at("int").signed_value()); |
| 607 |
| 608 ASSERT_TRUE(base::ContainsKey(collected_data, "uint")); |
| 609 EXPECT_EQ(TypedValue::kUnsignedValue, collected_data.at("uint").value_case()); |
| 610 EXPECT_EQ(9999U, collected_data.at("uint").unsigned_value()); |
| 611 |
| 612 ASSERT_TRUE(base::ContainsKey(collected_data, "bool")); |
| 613 EXPECT_EQ(TypedValue::kBoolValue, collected_data.at("bool").value_case()); |
| 614 EXPECT_TRUE(collected_data.at("bool").bool_value()); |
| 615 |
| 616 ASSERT_TRUE(base::ContainsKey(collected_data, "ref")); |
| 617 EXPECT_EQ(TypedValue::kBytesReference, collected_data.at("ref").value_case()); |
| 618 const TypedValue::Reference& ref = collected_data.at("ref").bytes_reference(); |
| 619 EXPECT_EQ(reinterpret_cast<uintptr_t>(string1), ref.address()); |
| 620 EXPECT_EQ(strlen(string1), static_cast<uint64_t>(ref.size())); |
| 621 |
| 622 ASSERT_TRUE(base::ContainsKey(collected_data, "sref")); |
| 623 EXPECT_EQ(TypedValue::kStringReference, |
| 624 collected_data.at("sref").value_case()); |
| 625 const TypedValue::Reference& sref = |
| 626 collected_data.at("sref").string_reference(); |
| 627 EXPECT_EQ(reinterpret_cast<uintptr_t>(string2), sref.address()); |
| 628 EXPECT_EQ(strlen(string2), static_cast<uint64_t>(sref.size())); |
| 629 } |
| 630 |
541 } // namespace browser_watcher | 631 } // namespace browser_watcher |
OLD | NEW |