Chromium Code Reviews| 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 mem_reference, GlobalActivityTracker::kTypeIdActivityTracker, | 112 mem_reference, GlobalActivityTracker::kTypeIdActivityTracker, |
| 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 } |
| 122 void PerformBasicReportValidation(const StabilityReport& report) { | |
| 123 // One report with one thread that has the expected name and id. | |
| 124 ASSERT_EQ(1, report.process_states_size()); | |
| 125 const ProcessState& process_state = report.process_states(0); | |
| 126 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); | |
| 127 ASSERT_EQ(1, process_state.threads_size()); | |
| 128 const ThreadState& thread_state = process_state.threads(0); | |
| 129 EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name()); | |
| 130 #if defined(OS_WIN) | |
| 131 EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id()); | |
| 132 #elif defined(OS_POSIX) | |
| 133 EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(), | |
| 134 thread_state.thread_id()); | |
| 135 #endif | |
| 136 } | |
| 121 | 137 |
| 122 const FilePath& debug_file_path() const { return debug_file_path_; } | 138 const FilePath& debug_file_path() const { return debug_file_path_; } |
| 123 | 139 |
| 124 protected: | 140 protected: |
| 125 base::ScopedTempDir temp_dir_; | 141 base::ScopedTempDir temp_dir_; |
| 126 FilePath debug_file_path_; | 142 FilePath debug_file_path_; |
| 127 | 143 |
| 128 std::unique_ptr<PersistentMemoryAllocator> allocator_; | 144 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
| 129 std::unique_ptr<ThreadActivityTracker> tracker_; | 145 std::unique_ptr<ThreadActivityTracker> tracker_; |
| 130 }; | 146 }; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 156 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); | 172 GlobalActivityTracker::kTypeIdUserDataRecordFree, 1024U, 10U, false); |
| 157 std::unique_ptr<ActivityUserData> user_data = | 173 std::unique_ptr<ActivityUserData> user_data = |
| 158 tracker_->GetUserData(activity_id, &user_data_allocator); | 174 tracker_->GetUserData(activity_id, &user_data_allocator); |
| 159 user_data->SetInt("some_int", 42); | 175 user_data->SetInt("some_int", 42); |
| 160 | 176 |
| 161 // Validate collection returns the expected report. | 177 // Validate collection returns the expected report. |
| 162 StabilityReport report; | 178 StabilityReport report; |
| 163 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | 179 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); |
| 164 | 180 |
| 165 // Validate the report. | 181 // Validate the report. |
| 166 ASSERT_EQ(1, report.process_states_size()); | 182 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); |
| 167 const ProcessState& process_state = report.process_states(0); | 183 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 | 184 |
| 180 EXPECT_EQ(7, thread_state.activity_count()); | 185 EXPECT_EQ(7, thread_state.activity_count()); |
| 181 ASSERT_EQ(6, thread_state.activities_size()); | 186 ASSERT_EQ(6, thread_state.activities_size()); |
| 182 { | 187 { |
| 183 const Activity& activity = thread_state.activities(0); | 188 const Activity& activity = thread_state.activities(0); |
| 184 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); | 189 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); |
| 185 EXPECT_EQ(kTaskOrigin, activity.origin_address()); | 190 EXPECT_EQ(kTaskOrigin, activity.origin_address()); |
| 186 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); | 191 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); |
| 187 EXPECT_EQ(0U, activity.user_data().size()); | 192 EXPECT_EQ(0U, activity.user_data().size()); |
| 188 } | 193 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 216 } | 221 } |
| 217 { | 222 { |
| 218 const Activity& activity = thread_state.activities(5); | 223 const Activity& activity = thread_state.activities(5); |
| 219 EXPECT_EQ(Activity::ACT_GENERIC, activity.type()); | 224 EXPECT_EQ(Activity::ACT_GENERIC, activity.type()); |
| 220 EXPECT_EQ(kGenericId, activity.generic_id()); | 225 EXPECT_EQ(kGenericId, activity.generic_id()); |
| 221 EXPECT_EQ(kGenericData, activity.generic_data()); | 226 EXPECT_EQ(kGenericData, activity.generic_data()); |
| 222 EXPECT_EQ(0U, activity.user_data().size()); | 227 EXPECT_EQ(0U, activity.user_data().size()); |
| 223 } | 228 } |
| 224 } | 229 } |
| 225 | 230 |
| 231 TEST_F(StabilityReportExtractorThreadTrackerTest, CollectException) { | |
| 232 const void* expected_pc = reinterpret_cast<void*>(0xCAFE); | |
| 233 const void* expected_address = nullptr; | |
| 234 const uint32_t expected_code = 42U; | |
| 235 | |
| 236 // Record an exception. | |
| 237 const int64_t timestamp = base::Time::Now().ToInternalValue(); | |
| 238 tracker_->RecordExceptionActivity(expected_pc, expected_address, | |
| 239 base::debug::Activity::ACT_EXCEPTION, | |
| 240 ActivityData::ForException(expected_code)); | |
| 241 | |
| 242 // Collect report and validate. | |
| 243 StabilityReport report; | |
| 244 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | |
| 245 | |
| 246 // Validate the presence of the exception. | |
| 247 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); | |
| 248 const ThreadState& thread_state = report.process_states(0).threads(0); | |
| 249 ASSERT_TRUE(thread_state.has_exception()); | |
| 250 const Exception& exception = thread_state.exception(); | |
| 251 EXPECT_EQ(expected_code, exception.code()); | |
| 252 EXPECT_EQ(expected_pc, reinterpret_cast<void*>(exception.program_counter())); | |
| 253 EXPECT_EQ(expected_address, | |
| 254 reinterpret_cast<void*>(exception.exception_address())); | |
| 255 const int64_t tolerance_us = 1000ULL; | |
| 256 EXPECT_LE(std::abs(timestamp - exception.time()), tolerance_us); | |
| 257 } | |
| 258 | |
| 259 TEST_F(StabilityReportExtractorThreadTrackerTest, CollectNoException) { | |
|
Sigurður Ásgeirsson
2017/06/09 13:55:15
nice testing, I like it!
manzagop (departed)
2017/06/09 21:27:35
Thanks you sir! Ack.
| |
| 260 // Record something. | |
| 261 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), | |
| 262 base::debug::Activity::ACT_TASK_RUN, | |
| 263 ActivityData::ForTask(kTaskSequenceNum)); | |
| 264 | |
| 265 // Collect report and validate there is no exception. | |
| 266 StabilityReport report; | |
| 267 ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report)); | |
| 268 ASSERT_NO_FATAL_FAILURE(PerformBasicReportValidation(report)); | |
| 269 const ThreadState& thread_state = report.process_states(0).threads(0); | |
| 270 ASSERT_FALSE(thread_state.has_exception()); | |
| 271 } | |
| 272 | |
| 226 // Tests stability report extraction. | 273 // Tests stability report extraction. |
| 227 class StabilityReportExtractorTest : public testing::Test { | 274 class StabilityReportExtractorTest : public testing::Test { |
| 228 public: | 275 public: |
| 229 const int kMemorySize = 1 << 20; // 1MiB | 276 const int kMemorySize = 1 << 20; // 1MiB |
| 230 | 277 |
| 231 StabilityReportExtractorTest() {} | 278 StabilityReportExtractorTest() {} |
| 232 ~StabilityReportExtractorTest() override { | 279 ~StabilityReportExtractorTest() override { |
| 233 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); | 280 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 234 if (global_tracker) { | 281 if (global_tracker) { |
| 235 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); | 282 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 400 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); | 447 EXPECT_EQ("CAFECAFE2d000", collected_module.code_identifier()); |
| 401 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); | 448 EXPECT_EQ(module_info.debug_file, collected_module.debug_file()); |
| 402 EXPECT_EQ("1122334455667788ABCD0123456789AB1", | 449 EXPECT_EQ("1122334455667788ABCD0123456789AB1", |
| 403 collected_module.debug_identifier()); | 450 collected_module.debug_identifier()); |
| 404 EXPECT_EQ("", collected_module.version()); | 451 EXPECT_EQ("", collected_module.version()); |
| 405 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); | 452 EXPECT_EQ(0LL, collected_module.shrink_down_delta()); |
| 406 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); | 453 EXPECT_EQ(!module_info.is_loaded, collected_module.is_unloaded()); |
| 407 } | 454 } |
| 408 | 455 |
| 409 } // namespace browser_watcher | 456 } // namespace browser_watcher |
| OLD | NEW |