extended_crash_reporting_win_unittest.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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
  3. // found in the LICENSE file.
  4. #include "components/browser_watcher/extended_crash_reporting.h"
  5. #include <windows.h>
  6. #include "base/command_line.h"
  7. #include "base/debug/activity_analyzer.h"
  8. #include "base/debug/activity_tracker.h"
  9. #include "base/files/file_path.h"
  10. #include "base/files/file_util.h"
  11. #include "base/files/scoped_temp_dir.h"
  12. #include "base/metrics/persistent_memory_allocator.h"
  13. #include "base/process/process.h"
  14. #include "base/test/multiprocess_test.h"
  15. #include "base/test/scoped_feature_list.h"
  16. #include "build/build_config.h"
  17. #include "components/browser_watcher/activity_report.pb.h"
  18. #include "components/browser_watcher/activity_report_extractor.h"
  19. #include "components/browser_watcher/activity_tracker_annotation.h"
  20. #include "components/browser_watcher/features.h"
  21. #include "components/crash/core/common/crash_key.h"
  22. #include "testing/gtest/include/gtest/gtest.h"
  23. #include "testing/multiprocess_func_list.h"
  24. #include "third_party/crashpad/crashpad/client/annotation_list.h"
  25. namespace browser_watcher {
  26. namespace {
  27. crashpad::Annotation* GetActivtyTrackerAnnotation() {
  28. crashpad::AnnotationList* annotation_list = crashpad::AnnotationList::Get();
  29. for (auto it = annotation_list->begin(); it != annotation_list->end(); ++it) {
  30. if (strcmp(ActivityTrackerAnnotation::kAnnotationName, (*it)->name()) ==
  31. 0 &&
  32. ActivityTrackerAnnotation::kAnnotationType == (*it)->type()) {
  33. return *it;
  34. }
  35. }
  36. return nullptr;
  37. }
  38. bool IsNullOrEmpty(crashpad::Annotation* annotation) {
  39. return annotation == nullptr || annotation->size() == 0;
  40. }
  41. bool IsNonEmpty(crashpad::Annotation* annotation) {
  42. return annotation != nullptr && annotation->size() > 0;
  43. }
  44. using base::debug::GlobalActivityAnalyzer;
  45. using base::debug::GlobalActivityTracker;
  46. constexpr uint32_t kExceptionCode = 42U;
  47. constexpr uint32_t kExceptionFlagContinuable = 0U;
  48. } // namespace
  49. class ExtendedCrashReportingTest : public testing::Test {
  50. public:
  51. ExtendedCrashReportingTest() {}
  52. ~ExtendedCrashReportingTest() override {
  53. GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
  54. if (global_tracker) {
  55. global_tracker->ReleaseTrackerForCurrentThreadForTesting();
  56. delete global_tracker;
  57. }
  58. }
  59. void SetUp() override {
  60. testing::Test::SetUp();
  61. // Initialize the crash keys, which will also reset the activity tracker
  62. // annotation if it's been used in previous tests.
  63. crash_reporter::InitializeCrashKeysForTesting();
  64. }
  65. void TearDown() override {
  66. ExtendedCrashReporting::TearDownForTesting();
  67. crash_reporter::ResetCrashKeysForTesting();
  68. testing::Test::TearDown();
  69. }
  70. std::unique_ptr<GlobalActivityAnalyzer> CreateAnalyzer() {
  71. GlobalActivityTracker* tracker = GlobalActivityTracker::Get();
  72. EXPECT_TRUE(tracker);
  73. base::PersistentMemoryAllocator* tmp = tracker->allocator();
  74. return GlobalActivityAnalyzer::CreateWithAllocator(
  75. std::make_unique<base::PersistentMemoryAllocator>(
  76. const_cast<void*>(tmp->data()), tmp->size(), 0u, 0u, "Copy", true));
  77. }
  78. };
  79. TEST_F(ExtendedCrashReportingTest, DisabledByDefault) {
  80. EXPECT_EQ(nullptr, ExtendedCrashReporting::SetUpIfEnabled(
  81. ExtendedCrashReporting::kBrowserProcess));
  82. EXPECT_EQ(nullptr, ExtendedCrashReporting::GetInstance());
  83. }
  84. TEST_F(ExtendedCrashReportingTest, SetUpIsEnabledByFeatureFlag) {
  85. base::test::ScopedFeatureList feature_list;
  86. feature_list.InitAndEnableFeature(kExtendedCrashReportingFeature);
  87. ExtendedCrashReporting* reporting = ExtendedCrashReporting::SetUpIfEnabled(
  88. ExtendedCrashReporting::kBrowserProcess);
  89. EXPECT_NE(nullptr, reporting);
  90. EXPECT_EQ(reporting, ExtendedCrashReporting::GetInstance());
  91. }
  92. TEST_F(ExtendedCrashReportingTest, RecordsAnnotation) {
  93. // Make sure the annotation doesn't exist before initialization.
  94. crashpad::Annotation* annotation = GetActivtyTrackerAnnotation();
  95. EXPECT_TRUE(IsNullOrEmpty(annotation));
  96. ExtendedCrashReporting::SetUpForTesting();
  97. EXPECT_NE(nullptr, ExtendedCrashReporting::GetInstance());
  98. EXPECT_TRUE(IsNonEmpty(GetActivtyTrackerAnnotation()));
  99. }
  100. #if defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_WIN)
  101. // The test does not pass under WinASan. See crbug.com/809524.
  102. #define MAYBE_CrashingTest DISABLED_CrashingTest
  103. #else
  104. #define MAYBE_CrashingTest CrashingTest
  105. #endif
  106. TEST_F(ExtendedCrashReportingTest, MAYBE_CrashingTest) {
  107. ExtendedCrashReporting::SetUpForTesting();
  108. ExtendedCrashReporting* extended_crash_reporting =
  109. ExtendedCrashReporting::GetInstance();
  110. ASSERT_NE(nullptr, extended_crash_reporting);
  111. // Raise an exception, then continue.
  112. __try {
  113. ::RaiseException(kExceptionCode, kExceptionFlagContinuable, 0U, nullptr);
  114. } __except (EXCEPTION_CONTINUE_EXECUTION) {
  115. }
  116. // Collect the report.
  117. StabilityReport report;
  118. ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
  119. // Validate expectations.
  120. ASSERT_EQ(1, report.process_states_size());
  121. const ProcessState& process_state = report.process_states(0);
  122. ASSERT_EQ(1, process_state.threads_size());
  123. bool thread_found = false;
  124. for (const ThreadState& thread : process_state.threads()) {
  125. if (thread.thread_id() == ::GetCurrentThreadId()) {
  126. thread_found = true;
  127. ASSERT_TRUE(thread.has_exception());
  128. const Exception& exception = thread.exception();
  129. EXPECT_EQ(kExceptionCode, exception.code());
  130. EXPECT_NE(0ULL, exception.program_counter());
  131. EXPECT_NE(0ULL, exception.exception_address());
  132. EXPECT_NE(0LL, exception.time());
  133. }
  134. }
  135. ASSERT_TRUE(thread_found);
  136. }
  137. } // namespace browser_watcher