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 |