123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/browser_watcher/extended_crash_reporting.h"
- #include <windows.h>
- #include "base/command_line.h"
- #include "base/debug/activity_analyzer.h"
- #include "base/debug/activity_tracker.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/metrics/persistent_memory_allocator.h"
- #include "base/process/process.h"
- #include "base/test/multiprocess_test.h"
- #include "base/test/scoped_feature_list.h"
- #include "build/build_config.h"
- #include "components/browser_watcher/activity_report.pb.h"
- #include "components/browser_watcher/activity_report_extractor.h"
- #include "components/browser_watcher/activity_tracker_annotation.h"
- #include "components/browser_watcher/features.h"
- #include "components/crash/core/common/crash_key.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/multiprocess_func_list.h"
- #include "third_party/crashpad/crashpad/client/annotation_list.h"
- namespace browser_watcher {
- namespace {
- crashpad::Annotation* GetActivtyTrackerAnnotation() {
- crashpad::AnnotationList* annotation_list = crashpad::AnnotationList::Get();
- for (auto it = annotation_list->begin(); it != annotation_list->end(); ++it) {
- if (strcmp(ActivityTrackerAnnotation::kAnnotationName, (*it)->name()) ==
- 0 &&
- ActivityTrackerAnnotation::kAnnotationType == (*it)->type()) {
- return *it;
- }
- }
- return nullptr;
- }
- bool IsNullOrEmpty(crashpad::Annotation* annotation) {
- return annotation == nullptr || annotation->size() == 0;
- }
- bool IsNonEmpty(crashpad::Annotation* annotation) {
- return annotation != nullptr && annotation->size() > 0;
- }
- using base::debug::GlobalActivityAnalyzer;
- using base::debug::GlobalActivityTracker;
- constexpr uint32_t kExceptionCode = 42U;
- constexpr uint32_t kExceptionFlagContinuable = 0U;
- } // namespace
- class ExtendedCrashReportingTest : public testing::Test {
- public:
- ExtendedCrashReportingTest() {}
- ~ExtendedCrashReportingTest() override {
- GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
- if (global_tracker) {
- global_tracker->ReleaseTrackerForCurrentThreadForTesting();
- delete global_tracker;
- }
- }
- void SetUp() override {
- testing::Test::SetUp();
- // Initialize the crash keys, which will also reset the activity tracker
- // annotation if it's been used in previous tests.
- crash_reporter::InitializeCrashKeysForTesting();
- }
- void TearDown() override {
- ExtendedCrashReporting::TearDownForTesting();
- crash_reporter::ResetCrashKeysForTesting();
- testing::Test::TearDown();
- }
- std::unique_ptr<GlobalActivityAnalyzer> CreateAnalyzer() {
- GlobalActivityTracker* tracker = GlobalActivityTracker::Get();
- EXPECT_TRUE(tracker);
- base::PersistentMemoryAllocator* tmp = tracker->allocator();
- return GlobalActivityAnalyzer::CreateWithAllocator(
- std::make_unique<base::PersistentMemoryAllocator>(
- const_cast<void*>(tmp->data()), tmp->size(), 0u, 0u, "Copy", true));
- }
- };
- TEST_F(ExtendedCrashReportingTest, DisabledByDefault) {
- EXPECT_EQ(nullptr, ExtendedCrashReporting::SetUpIfEnabled(
- ExtendedCrashReporting::kBrowserProcess));
- EXPECT_EQ(nullptr, ExtendedCrashReporting::GetInstance());
- }
- TEST_F(ExtendedCrashReportingTest, SetUpIsEnabledByFeatureFlag) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kExtendedCrashReportingFeature);
- ExtendedCrashReporting* reporting = ExtendedCrashReporting::SetUpIfEnabled(
- ExtendedCrashReporting::kBrowserProcess);
- EXPECT_NE(nullptr, reporting);
- EXPECT_EQ(reporting, ExtendedCrashReporting::GetInstance());
- }
- TEST_F(ExtendedCrashReportingTest, RecordsAnnotation) {
- // Make sure the annotation doesn't exist before initialization.
- crashpad::Annotation* annotation = GetActivtyTrackerAnnotation();
- EXPECT_TRUE(IsNullOrEmpty(annotation));
- ExtendedCrashReporting::SetUpForTesting();
- EXPECT_NE(nullptr, ExtendedCrashReporting::GetInstance());
- EXPECT_TRUE(IsNonEmpty(GetActivtyTrackerAnnotation()));
- }
- #if defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_WIN)
- // The test does not pass under WinASan. See crbug.com/809524.
- #define MAYBE_CrashingTest DISABLED_CrashingTest
- #else
- #define MAYBE_CrashingTest CrashingTest
- #endif
- TEST_F(ExtendedCrashReportingTest, MAYBE_CrashingTest) {
- ExtendedCrashReporting::SetUpForTesting();
- ExtendedCrashReporting* extended_crash_reporting =
- ExtendedCrashReporting::GetInstance();
- ASSERT_NE(nullptr, extended_crash_reporting);
- // Raise an exception, then continue.
- __try {
- ::RaiseException(kExceptionCode, kExceptionFlagContinuable, 0U, nullptr);
- } __except (EXCEPTION_CONTINUE_EXECUTION) {
- }
- // Collect the report.
- StabilityReport report;
- ASSERT_EQ(SUCCESS, Extract(CreateAnalyzer(), &report));
- // Validate expectations.
- ASSERT_EQ(1, report.process_states_size());
- const ProcessState& process_state = report.process_states(0);
- ASSERT_EQ(1, process_state.threads_size());
- bool thread_found = false;
- for (const ThreadState& thread : process_state.threads()) {
- if (thread.thread_id() == ::GetCurrentThreadId()) {
- thread_found = true;
- ASSERT_TRUE(thread.has_exception());
- const Exception& exception = thread.exception();
- EXPECT_EQ(kExceptionCode, exception.code());
- EXPECT_NE(0ULL, exception.program_counter());
- EXPECT_NE(0ULL, exception.exception_address());
- EXPECT_NE(0LL, exception.time());
- }
- }
- ASSERT_TRUE(thread_found);
- }
- } // namespace browser_watcher
|