| 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_analyzer.h" |
| 16 #include "base/debug/activity_tracker.h" | 16 #include "base/debug/activity_tracker.h" |
| 17 #include "base/files/file.h" | 17 #include "base/files/file.h" |
| 18 #include "base/files/file_path.h" | 18 #include "base/files/file_path.h" |
| 19 #include "base/files/file_util.h" | 19 #include "base/files/file_util.h" |
| 20 #include "base/files/memory_mapped_file.h" | 20 #include "base/files/memory_mapped_file.h" |
| 21 #include "base/files/scoped_file.h" | 21 #include "base/files/scoped_file.h" |
| 22 #include "base/files/scoped_temp_dir.h" | 22 #include "base/files/scoped_temp_dir.h" |
| 23 #include "base/memory/ptr_util.h" | 23 #include "base/memory/ptr_util.h" |
| 24 #include "base/metrics/persistent_memory_allocator.h" | 24 #include "base/metrics/persistent_memory_allocator.h" |
| 25 #include "base/process/process_handle.h" | 25 #include "base/process/process_handle.h" |
| 26 #include "base/stl_util.h" | 26 #include "base/stl_util.h" |
| 27 #include "base/threading/platform_thread.h" | 27 #include "base/threading/platform_thread.h" |
| 28 #include "components/browser_watcher/stability_data_names.h" |
| 28 #include "testing/gmock/include/gmock/gmock.h" | 29 #include "testing/gmock/include/gmock/gmock.h" |
| 29 #include "testing/gtest/include/gtest/gtest.h" | 30 #include "testing/gtest/include/gtest/gtest.h" |
| 30 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | 31 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
| 31 | 32 |
| 32 namespace browser_watcher { | 33 namespace browser_watcher { |
| 33 | 34 |
| 34 using base::debug::ActivityData; | 35 using base::debug::ActivityData; |
| 35 using base::debug::ActivityTrackerMemoryAllocator; | 36 using base::debug::ActivityTrackerMemoryAllocator; |
| 36 using base::debug::ActivityUserData; | 37 using base::debug::ActivityUserData; |
| 37 using base::debug::GlobalActivityTracker; | 38 using base::debug::GlobalActivityTracker; |
| 38 using base::debug::ThreadActivityTracker; | 39 using base::debug::ThreadActivityTracker; |
| 39 using base::File; | 40 using base::File; |
| 40 using base::FilePersistentMemoryAllocator; | 41 using base::FilePersistentMemoryAllocator; |
| 41 using base::MemoryMappedFile; | 42 using base::MemoryMappedFile; |
| 42 using base::PersistentMemoryAllocator; | 43 using base::PersistentMemoryAllocator; |
| 43 using base::WrapUnique; | 44 using base::WrapUnique; |
| 44 using crashpad::CrashReportDatabase; | 45 using crashpad::CrashReportDatabase; |
| 45 using crashpad::Settings; | 46 using crashpad::Settings; |
| 46 using crashpad::UUID; | 47 using crashpad::UUID; |
| 47 using testing::_; | 48 using testing::_; |
| 48 using testing::Return; | 49 using testing::Return; |
| 49 using testing::SetArgPointee; | 50 using testing::SetArgPointee; |
| 50 | 51 |
| 51 namespace { | 52 namespace { |
| 52 | 53 |
| 53 const char kProductName[] = "TestProduct"; | 54 const char kProductName[] = "TestProduct"; |
| 54 const char kVersionNumber[] = "TestVersionNumber"; | 55 const char kVersionNumber[] = "TestVersionNumber"; |
| 55 const char kChannelName[] = "TestChannel"; | 56 const char kChannelName[] = "TestChannel"; |
| 56 | 57 |
| 58 void ContainsKeyValue( |
| 59 const google::protobuf::Map<std::string, TypedValue>& data, |
| 60 const std::string& key, |
| 61 const std::string& value) { |
| 62 auto it = data.find(key); |
| 63 ASSERT_TRUE(it != data.end()); |
| 64 EXPECT_EQ(TypedValue::kStringValue, it->second.value_case()); |
| 65 EXPECT_EQ(value, it->second.string_value()); |
| 66 } |
| 67 |
| 57 // Exposes a public constructor in order to create a dummy database. | 68 // Exposes a public constructor in order to create a dummy database. |
| 58 class MockCrashReportDatabase : public CrashReportDatabase { | 69 class MockCrashReportDatabase : public CrashReportDatabase { |
| 59 public: | 70 public: |
| 60 MockCrashReportDatabase() {} | 71 MockCrashReportDatabase() {} |
| 61 MOCK_METHOD0(GetSettings, Settings*()); | 72 MOCK_METHOD0(GetSettings, Settings*()); |
| 62 MOCK_METHOD1(PrepareNewCrashReport, | 73 MOCK_METHOD1(PrepareNewCrashReport, |
| 63 CrashReportDatabase::CrashReportDatabase::OperationStatus( | 74 CrashReportDatabase::CrashReportDatabase::OperationStatus( |
| 64 NewReport** report)); | 75 NewReport** report)); |
| 65 MOCK_METHOD2(FinishedWritingCrashReport, | 76 MOCK_METHOD2(FinishedWritingCrashReport, |
| 66 CrashReportDatabase::CrashReportDatabase::OperationStatus( | 77 CrashReportDatabase::CrashReportDatabase::OperationStatus( |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 return SUCCESS; | 122 return SUCCESS; |
| 112 } | 123 } |
| 113 | 124 |
| 114 MOCK_METHOD3(GetDebugStateFilePaths, | 125 MOCK_METHOD3(GetDebugStateFilePaths, |
| 115 std::vector<base::FilePath>( | 126 std::vector<base::FilePath>( |
| 116 const base::FilePath& debug_info_dir, | 127 const base::FilePath& debug_info_dir, |
| 117 const base::FilePath::StringType& debug_file_pattern, | 128 const base::FilePath::StringType& debug_file_pattern, |
| 118 const std::set<base::FilePath>&)); | 129 const std::set<base::FilePath>&)); |
| 119 MOCK_METHOD1(CollectRaw, StabilityReport*(const base::FilePath&)); | 130 MOCK_METHOD1(CollectRaw, StabilityReport*(const base::FilePath&)); |
| 120 MOCK_METHOD4(WriteReportToMinidump, | 131 MOCK_METHOD4(WriteReportToMinidump, |
| 121 bool(const StabilityReport& report, | 132 bool(StabilityReport* report, |
| 122 const crashpad::UUID& client_id, | 133 const crashpad::UUID& client_id, |
| 123 const crashpad::UUID& report_id, | 134 const crashpad::UUID& report_id, |
| 124 base::PlatformFile minidump_file)); | 135 base::PlatformFile minidump_file)); |
| 125 }; | 136 }; |
| 126 | 137 |
| 127 // Checks if two proto messages are the same based on their serializations. Note | 138 // Checks if two proto messages are the same based on their serializations. Note |
| 128 // this only works if serialization is deterministic, which is not guaranteed. | 139 // this only works if serialization is deterministic, which is not guaranteed. |
| 129 // In practice, serialization is deterministic (even for protocol buffers with | 140 // In practice, serialization is deterministic (even for protocol buffers with |
| 130 // maps) and such matchers are common in the Chromium code base. Also note that | 141 // maps) and such matchers are common in the Chromium code base. Also note that |
| 131 // in the context of this test, false positive matches are the problem and these | 142 // in the context of this test, false positive matches are the problem and these |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 crashpad::UUID new_report_uuid; | 196 crashpad::UUID new_report_uuid; |
| 186 new_report_uuid.InitializeWithNew(); | 197 new_report_uuid.InitializeWithNew(); |
| 187 crashpad_report_ = {minidump_file.GetPlatformFile(), new_report_uuid, | 198 crashpad_report_ = {minidump_file.GetPlatformFile(), new_report_uuid, |
| 188 minidump_path}; | 199 minidump_path}; |
| 189 EXPECT_CALL(database_, PrepareNewCrashReport(_)) | 200 EXPECT_CALL(database_, PrepareNewCrashReport(_)) |
| 190 .Times(1) | 201 .Times(1) |
| 191 .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), | 202 .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), |
| 192 Return(CrashReportDatabase::kNoError))); | 203 Return(CrashReportDatabase::kNoError))); |
| 193 | 204 |
| 194 EXPECT_CALL(collector_, | 205 EXPECT_CALL(collector_, |
| 195 WriteReportToMinidump(EqualsProto(*stability_report), _, _, | 206 WriteReportToMinidump(stability_report, _, _, |
| 196 minidump_file.GetPlatformFile())) | 207 minidump_file.GetPlatformFile())) |
| 197 .Times(1) | 208 .Times(1) |
| 198 .WillOnce(Return(true)); | 209 .WillOnce(Return(true)); |
| 199 } | 210 } |
| 200 | 211 |
| 201 protected: | 212 protected: |
| 202 base::ScopedTempDir temp_dir_; | 213 base::ScopedTempDir temp_dir_; |
| 203 base::FilePath debug_file_; | 214 base::FilePath debug_file_; |
| 204 MockCrashReportDatabase database_; | 215 MockCrashReportDatabase database_; |
| 205 MockPostmortemReportCollector collector_; | 216 MockPostmortemReportCollector collector_; |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 // Collect the stability report. | 591 // Collect the stability report. |
| 581 PostmortemReportCollector collector(kProductName, kVersionNumber, | 592 PostmortemReportCollector collector(kProductName, kVersionNumber, |
| 582 kChannelName); | 593 kChannelName); |
| 583 std::unique_ptr<StabilityReport> report; | 594 std::unique_ptr<StabilityReport> report; |
| 584 ASSERT_EQ(PostmortemReportCollector::SUCCESS, | 595 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
| 585 collector.Collect(debug_file_path(), &report)); | 596 collector.Collect(debug_file_path(), &report)); |
| 586 ASSERT_NE(nullptr, report); | 597 ASSERT_NE(nullptr, report); |
| 587 | 598 |
| 588 // Validate the report's user data. | 599 // Validate the report's user data. |
| 589 const auto& collected_data = report->global_data(); | 600 const auto& collected_data = report->global_data(); |
| 590 ASSERT_EQ(8U, collected_data.size()); | 601 ASSERT_EQ(12U, collected_data.size()); |
| 591 | 602 |
| 592 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); | 603 ASSERT_TRUE(base::ContainsKey(collected_data, "raw")); |
| 593 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); | 604 EXPECT_EQ(TypedValue::kBytesValue, collected_data.at("raw").value_case()); |
| 594 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); | 605 EXPECT_EQ("foo", collected_data.at("raw").bytes_value()); |
| 595 | 606 |
| 596 ASSERT_TRUE(base::ContainsKey(collected_data, "string")); | 607 ASSERT_TRUE(base::ContainsKey(collected_data, "string")); |
| 597 EXPECT_EQ(TypedValue::kStringValue, collected_data.at("string").value_case()); | 608 EXPECT_EQ(TypedValue::kStringValue, collected_data.at("string").value_case()); |
| 598 EXPECT_EQ("bar", collected_data.at("string").string_value()); | 609 EXPECT_EQ("bar", collected_data.at("string").string_value()); |
| 599 | 610 |
| 600 ASSERT_TRUE(base::ContainsKey(collected_data, "char")); | 611 ASSERT_TRUE(base::ContainsKey(collected_data, "char")); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 619 EXPECT_EQ(reinterpret_cast<uintptr_t>(string1), ref.address()); | 630 EXPECT_EQ(reinterpret_cast<uintptr_t>(string1), ref.address()); |
| 620 EXPECT_EQ(strlen(string1), static_cast<uint64_t>(ref.size())); | 631 EXPECT_EQ(strlen(string1), static_cast<uint64_t>(ref.size())); |
| 621 | 632 |
| 622 ASSERT_TRUE(base::ContainsKey(collected_data, "sref")); | 633 ASSERT_TRUE(base::ContainsKey(collected_data, "sref")); |
| 623 EXPECT_EQ(TypedValue::kStringReference, | 634 EXPECT_EQ(TypedValue::kStringReference, |
| 624 collected_data.at("sref").value_case()); | 635 collected_data.at("sref").value_case()); |
| 625 const TypedValue::Reference& sref = | 636 const TypedValue::Reference& sref = |
| 626 collected_data.at("sref").string_reference(); | 637 collected_data.at("sref").string_reference(); |
| 627 EXPECT_EQ(reinterpret_cast<uintptr_t>(string2), sref.address()); | 638 EXPECT_EQ(reinterpret_cast<uintptr_t>(string2), sref.address()); |
| 628 EXPECT_EQ(strlen(string2), static_cast<uint64_t>(sref.size())); | 639 EXPECT_EQ(strlen(string2), static_cast<uint64_t>(sref.size())); |
| 640 |
| 641 // Reporter's version details. |
| 642 ContainsKeyValue(collected_data, kStabilityReporterProduct, kProductName); |
| 643 ContainsKeyValue(collected_data, kStabilityReporterChannel, kChannelName); |
| 644 #if defined(ARCH_CPU_X86) |
| 645 ContainsKeyValue(collected_data, kStabilityReporterPlatform, "Win32"); |
| 646 #elif defined(ARCH_CPU_X86_64) |
| 647 ContainsKeyValue(collected_data, kStabilityReporterPlatform, "Win64"); |
| 648 #endif |
| 649 ContainsKeyValue(collected_data, kStabilityReporterVersion, kVersionNumber); |
| 629 } | 650 } |
| 630 | 651 |
| 631 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, | 652 TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, |
| 632 ModuleCollection) { | 653 ModuleCollection) { |
| 633 // Record some module information. | 654 // Record some module information. |
| 634 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, | 655 GlobalActivityTracker::CreateWithFile(debug_file_path(), kMemorySize, 0ULL, |
| 635 "", 3); | 656 "", 3); |
| 636 | 657 |
| 637 base::debug::GlobalActivityTracker::ModuleInfo module_info = {}; | 658 base::debug::GlobalActivityTracker::ModuleInfo module_info = {}; |
| 638 module_info.is_loaded = true; | 659 module_info.is_loaded = true; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); | 691 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); |
| 671 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); | 692 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); |
| 672 EXPECT_EQ("1122334455667788ABCD0123456789AB1", | 693 EXPECT_EQ("1122334455667788ABCD0123456789AB1", |
| 673 collected_module.debug_identifier()); | 694 collected_module.debug_identifier()); |
| 674 EXPECT_EQ("", collected_module.version()); | 695 EXPECT_EQ("", collected_module.version()); |
| 675 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); | 696 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); |
| 676 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); | 697 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); |
| 677 } | 698 } |
| 678 | 699 |
| 679 } // namespace browser_watcher | 700 } // namespace browser_watcher |
| OLD | NEW |