| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/stability_report_extractor.h" | 5 #include "components/browser_watcher/stability_report_extractor.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/debug/activity_tracker.h" | 10 #include "base/debug/activity_tracker.h" |
| 11 #include "base/files/file.h" | 11 #include "base/files/file.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/files/memory_mapped_file.h" | 13 #include "base/files/memory_mapped_file.h" |
| 14 #include "base/files/scoped_temp_dir.h" | 14 #include "base/files/scoped_temp_dir.h" |
| 15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 16 #include "base/metrics/persistent_memory_allocator.h" | 16 #include "base/metrics/persistent_memory_allocator.h" |
| 17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 18 #include "base/time/time.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 19 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | 20 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
| 20 | 21 |
| 21 namespace browser_watcher { | 22 namespace browser_watcher { |
| 22 | 23 |
| 23 using base::debug::ActivityData; | 24 using base::debug::ActivityData; |
| 24 using base::debug::ActivityTrackerMemoryAllocator; | 25 using base::debug::ActivityTrackerMemoryAllocator; |
| 25 using base::debug::ActivityUserData; | 26 using base::debug::ActivityUserData; |
| 26 using base::debug::GlobalActivityTracker; | 27 using base::debug::GlobalActivityTracker; |
| 27 using base::debug::ThreadActivityTracker; | 28 using base::debug::ThreadActivityTracker; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 PersistentMemoryAllocator::kSizeAny); | 113 PersistentMemoryAllocator::kSizeAny); |
| 113 if (mem_base == nullptr) | 114 if (mem_base == nullptr) |
| 114 return nullptr; | 115 return nullptr; |
| 115 | 116 |
| 116 // Make the allocation iterable so it can be found by other processes. | 117 // Make the allocation iterable so it can be found by other processes. |
| 117 allocator->MakeIterable(mem_reference); | 118 allocator->MakeIterable(mem_reference); |
| 118 | 119 |
| 119 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); | 120 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); |
| 120 } | 121 } |
| 121 | 122 |
| 123 void PerformBasicReportValidation(const StabilityReport& report) { |
| 124 // One report with one thread that has the expected name and id. |
| 125 ASSERT_EQ(1, report.process_states_size()); |
| 126 const ProcessState& process_state = report.process_states(0); |
| 127 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); |
| 128 ASSERT_EQ(1, process_state.threads_size()); |
| 129 const ThreadState& thread_state = process_state.threads(0); |
| 130 EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name()); |
| 131 #if defined(OS_WIN) |
| 132 EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id()); |
| 133 #elif defined(OS_POSIX) |
| 134 EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(), |
| 135 thread_state.thread_id()); |
| 136 #endif |
| 137 } |
| 138 |
| 122 const FilePath& debug_file_path() const { return debug_file_path_; } | 139 const FilePath& debug_file_path() const { return debug_file_path_; } |
| 123 | 140 |
| 124 protected: | 141 protected: |
| 125 base::ScopedTempDir temp_dir_; | 142 base::ScopedTempDir temp_dir_; |
| 126 FilePath debug_file_path_; | 143 FilePath debug_file_path_; |
| 127 | 144 |
| 128 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 145 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
| 129 std::unique_ptr<ThreadActivityTracker> tracker_; | 146 std::unique_ptr<ThreadActivityTracker> tracker_; |
| 130 }; | 147 }; |
| 131 | 148 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 156 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); | 173 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); |
| 157 std::unique_ptr<ActivityUserData> user_data = | 174 std::unique_ptr<ActivityUserData> user_data = |
| 158 tracker_->GetUserData(activity_id, &user_data_allocator); | 175 tracker_->GetUserData(activity_id, &user_data_allocator); |
| 159 user_data->SetInt("some_int", 42); | 176 user_data->SetInt("some_int", 42); |
| 160 | 177 |
| 161 // Validate collection returns the expected report. | 178 // Validate collection returns the expected report. |
| 162 StabilityReport report; | 179 StabilityReport report; |
| 163 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | 180 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); |
| 164 | 181 |
| 165 // Validate the report. | 182 // Validate the report. |
| 166 ASSERT_EQ(1, report.process_states_size()); | 183 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); |
| 167 const ProcessState& process_state = report.process_states(0); | 184 const ThreadState& thread_state = report.process_states(0).threads(0); |
| 168 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); | |
| 169 ASSERT_EQ(1, process_state.threads_size()); | |
| 170 | |
| 171 const ThreadState& thread_state = process_state.threads(0); | |
| 172 EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name()); | |
| 173 #if defined(OS_WIN) | |
| 174 EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id()); | |
| 175 #elif defined(OS_POSIX) | |
| 176 EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(), | |
| 177 thread_state.thread_id()); | |
| 178 #endif | |
| 179 | 185 |
| 180 EXPECT_EQ(7, thread_state.activity_count()); | 186 EXPECT_EQ(7, thread_state.activity_count()); |
| 181 ASSERT_EQ(6, thread_state.activities_size()); | 187 ASSERT_EQ(6, thread_state.activities_size()); |
| 182 { | 188 { |
| 183 const Activity& activity = thread_state.activities(0); | 189 const Activity& activity = thread_state.activities(0); |
| 184 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); | 190 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); |
| 185 EXPECT_EQ(kTaskOrigin, activity.origin_address()); | 191 EXPECT_EQ(kTaskOrigin, activity.origin_address()); |
| 186 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); | 192 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); |
| 187 EXPECT_EQ(0U, activity.user_data().size()); | 193 EXPECT_EQ(0U, activity.user_data().size()); |
| 188 } | 194 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 216 } | 222 } |
| 217 { | 223 { |
| 218 const Activity& activity = thread_state.activities(5); | 224 const Activity& activity = thread_state.activities(5); |
| 219 EXPECT_EQ(Activity::ACT_GENERIC, activity.type()); | 225 EXPECT_EQ(Activity::ACT_GENERIC, activity.type()); |
| 220 EXPECT_EQ(kGenericId, activity.generic_id()); | 226 EXPECT_EQ(kGenericId, activity.generic_id()); |
| 221 EXPECT_EQ(kGenericData, activity.generic_data()); | 227 EXPECT_EQ(kGenericData, activity.generic_data()); |
| 222 EXPECT_EQ(0U, activity.user_data().size()); | 228 EXPECT_EQ(0U, activity.user_data().size()); |
| 223 } | 229 } |
| 224 } | 230 } |
| 225 | 231 |
| 232 TEST_F(StabilityReportExtractorThreadTrackerTest, CollectException) { |
| 233 const void* expected_pc = reinterpret_cast<void*>(0xCAFE); |
| 234 const void* expected_address = nullptr; |
| 235 const uint32_t expected_code = 42U; |
| 236 |
| 237 // Record an exception. |
| 238 const int64_t timestamp = base::Time::Now().ToInternalValue(); |
| 239 tracker_->RecordExceptionActivity(expected_pc, expected_address, |
| 240 base::debug::Activity::ACT_EXCEPTION, |
| 241 ActivityData::ForException(expected_code)); |
| 242 |
| 243 // Collect report and validate. |
| 244 StabilityReport report; |
| 245 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); |
| 246 |
| 247 // Validate the presence of the exception. |
| 248 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); |
| 249 const ThreadState& thread_state = report.process_states(0).threads(0); |
| 250 ASSERT_TRUE(thread_state.has_exception()); |
| 251 const Exception& exception = thread_state.exception(); |
| 252 EXPECT_EQ(expected_code, exception.code()); |
| 253 EXPECT_EQ(expected_pc, reinterpret_cast<void*>(exception.program_counter())); |
| 254 EXPECT_EQ(expected_address, |
| 255 reinterpret_cast<void*>(exception.exception_address())); |
| 256 const int64_t tolerance_us = 1000ULL; |
| 257 EXPECT_LE(std::abs(timestamp - exception.time()), tolerance_us); |
| 258 } |
| 259 |
| 260 TEST_F(StabilityReportExtractorThreadTrackerTest, CollectNoException) { |
| 261 // Record something. |
| 262 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), |
| 263 base::debug::Activity::ACT_TASK_RUN, |
| 264 ActivityData::ForTask(kTaskSequenceNum)); |
| 265 |
| 266 // Collect report and validate there is no exception. |
| 267 StabilityReport report; |
| 268 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); |
| 269 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); |
| 270 const ThreadState& thread_state = report.process_states(0).threads(0); |
| 271 ASSERT_FALSE(thread_state.has_exception()); |
| 272 } |
| 273 |
| 226 // Tests stability report extraction. | 274 // Tests stability report extraction. |
| 227 class StabilityReportExtractorTest : public testing::Test { | 275 class StabilityReportExtractorTest : public testing::Test { |
| 228 public: | 276 public: |
| 229 const int kMemorySize = 1 << 20; // 1MiB | 277 const int kMemorySize = 1 << 20; // 1MiB |
| 230 | 278 |
| 231 StabilityReportExtractorTest() {} | 279 StabilityReportExtractorTest() {} |
| 232 ~StabilityReportExtractorTest() override { | 280 ~StabilityReportExtractorTest() override { |
| 233 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); | 281 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 234 if (global_tracker) { | 282 if (global_tracker) { |
| 235 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); | 283 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); | 448 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); |
| 401 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); | 449 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); |
| 402 EXPECT_EQ("1122334455667788ABCD0123456789AB1", | 450 EXPECT_EQ("1122334455667788ABCD0123456789AB1", |
| 403 collected_module.debug_identifier()); | 451 collected_module.debug_identifier()); |
| 404 EXPECT_EQ("", collected_module.version()); | 452 EXPECT_EQ("", collected_module.version()); |
| 405 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); | 453 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); |
| 406 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); | 454 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); |
| 407 } | 455 } |
| 408 | 456 |
| 409 } // namespace browser_watcher | 457 } // namespace browser_watcher |
| OLD | NEW |