OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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/postmortem_report_collector.h" | 5 #include "components/browser_watcher/postmortem_report_collector.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <set> | 10 #include <set> |
11 #include <string> | 11 #include <string> |
12 #include <utility> | 12 #include <utility> |
13 #include <vector> | 13 #include <vector> |
14 | 14 |
15 #include "base/debug/activity_tracker.h" | 15 #include "base/debug/activity_tracker.h" |
16 #include "base/files/file.h" | 16 #include "base/files/file.h" |
17 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
18 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
19 #include "base/files/memory_mapped_file.h" | 19 #include "base/files/memory_mapped_file.h" |
20 #include "base/files/scoped_file.h" | 20 #include "base/files/scoped_file.h" |
21 #include "base/files/scoped_temp_dir.h" | 21 #include "base/files/scoped_temp_dir.h" |
22 #include "base/memory/ptr_util.h" | 22 #include "base/memory/ptr_util.h" |
23 #include "base/metrics/persistent_memory_allocator.h" | 23 #include "base/metrics/persistent_memory_allocator.h" |
| 24 #include "base/process/process_handle.h" |
24 #include "base/threading/platform_thread.h" | 25 #include "base/threading/platform_thread.h" |
25 #include "testing/gmock/include/gmock/gmock.h" | 26 #include "testing/gmock/include/gmock/gmock.h" |
26 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
27 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | 28 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
28 | 29 |
29 namespace browser_watcher { | 30 namespace browser_watcher { |
30 | 31 |
31 using base::debug::Activity; | |
32 using base::debug::ActivityData; | 32 using base::debug::ActivityData; |
33 using base::debug::GlobalActivityTracker; | 33 using base::debug::GlobalActivityTracker; |
34 using base::debug::ThreadActivityTracker; | 34 using base::debug::ThreadActivityTracker; |
35 using base::File; | 35 using base::File; |
36 using base::FilePersistentMemoryAllocator; | 36 using base::FilePersistentMemoryAllocator; |
37 using base::MemoryMappedFile; | 37 using base::MemoryMappedFile; |
38 using base::PersistentMemoryAllocator; | 38 using base::PersistentMemoryAllocator; |
39 using base::WrapUnique; | 39 using base::WrapUnique; |
40 using crashpad::CrashReportDatabase; | 40 using crashpad::CrashReportDatabase; |
41 using crashpad::Settings; | 41 using crashpad::Settings; |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 kChannelName); | 319 kChannelName); |
320 std::unique_ptr<StabilityReport> report; | 320 std::unique_ptr<StabilityReport> report; |
321 ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA, | 321 ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA, |
322 collector.Collect(file_path, &report)); | 322 collector.Collect(file_path, &report)); |
323 } | 323 } |
324 | 324 |
325 namespace { | 325 namespace { |
326 | 326 |
327 // Parameters for the activity tracking. | 327 // Parameters for the activity tracking. |
328 const size_t kFileSize = 2 * 1024; | 328 const size_t kFileSize = 2 * 1024; |
329 const int kStackDepth = 4; | 329 const int kStackDepth = 5; |
330 const uint64_t kAllocatorId = 0; | 330 const uint64_t kAllocatorId = 0; |
331 const char kAllocatorName[] = "PostmortemReportCollectorCollectionTest"; | 331 const char kAllocatorName[] = "PostmortemReportCollectorCollectionTest"; |
| 332 const uint64_t kTaskSequenceNum = 42; |
| 333 const uintptr_t kTaskOrigin = 1000U; |
| 334 const uintptr_t kLockAddress = 1001U; |
| 335 const uintptr_t kEventAddress = 1002U; |
| 336 const int kThreadId = 43; |
| 337 const int kProcessId = 44; |
| 338 const int kAnotherThreadId = 45; |
332 | 339 |
333 } // namespace | 340 } // namespace |
334 | 341 |
335 class PostmortemReportCollectorCollectionTest : public testing::Test { | 342 class PostmortemReportCollectorCollectionTest : public testing::Test { |
336 public: | 343 public: |
337 // Create a proper debug file. | 344 // Create a proper debug file. |
338 void SetUp() override { | 345 void SetUp() override { |
339 testing::Test::SetUp(); | 346 testing::Test::SetUp(); |
340 | 347 |
341 // Create a file backed allocator. | 348 // Create a file backed allocator. |
342 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 349 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
343 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug_file.pma"); | 350 debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug_file.pma"); |
344 std::unique_ptr<PersistentMemoryAllocator> allocator = CreateAllocator(); | 351 allocator_ = CreateAllocator(); |
345 ASSERT_NE(nullptr, allocator); | 352 ASSERT_NE(nullptr, allocator_); |
346 | 353 |
347 size_t tracker_mem_size = | 354 size_t tracker_mem_size = |
348 ThreadActivityTracker::SizeForStackDepth(kStackDepth); | 355 ThreadActivityTracker::SizeForStackDepth(kStackDepth); |
349 ASSERT_GT(kFileSize, tracker_mem_size); | 356 ASSERT_GT(kFileSize, tracker_mem_size); |
350 | 357 |
351 // Create some debug data using trackers. | 358 // Create a tracker. |
352 std::unique_ptr<ThreadActivityTracker> tracker = | 359 tracker_ = CreateTracker(allocator_.get(), tracker_mem_size); |
353 CreateTracker(allocator.get(), tracker_mem_size); | 360 ASSERT_NE(nullptr, tracker_); |
354 ASSERT_NE(nullptr, tracker); | 361 ASSERT_TRUE(tracker_->IsValid()); |
355 ASSERT_TRUE(tracker->IsValid()); | |
356 | |
357 const void* dummy_task_origin = reinterpret_cast<void*>(0xCAFE); | |
358 const int dummy_task_sequence_num = 42; | |
359 tracker->PushActivity(dummy_task_origin, Activity::ACT_TASK_RUN, | |
360 ActivityData::ForTask(dummy_task_sequence_num)); | |
361 | |
362 // TODO(manzagop): flesh out the data (more trackers and content). | |
363 } | 362 } |
364 | 363 |
365 std::unique_ptr<PersistentMemoryAllocator> CreateAllocator() { | 364 std::unique_ptr<PersistentMemoryAllocator> CreateAllocator() { |
366 // Create the memory mapped file. | 365 // Create the memory mapped file. |
367 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); | 366 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); |
368 bool success = mmfile->Initialize( | 367 bool success = mmfile->Initialize( |
369 File(debug_file_path_, File::FLAG_CREATE | File::FLAG_READ | | 368 File(debug_file_path_, File::FLAG_CREATE | File::FLAG_READ | |
370 File::FLAG_WRITE | File::FLAG_SHARE_DELETE), | 369 File::FLAG_WRITE | File::FLAG_SHARE_DELETE), |
371 {0, static_cast<int64_t>(kFileSize)}, | 370 {0, static_cast<int64_t>(kFileSize)}, |
372 MemoryMappedFile::READ_WRITE_EXTEND); | 371 MemoryMappedFile::READ_WRITE_EXTEND); |
(...skipping 23 matching lines...) Expand all Loading... |
396 return nullptr; | 395 return nullptr; |
397 | 396 |
398 // Make the allocation iterable so it can be found by other processes. | 397 // Make the allocation iterable so it can be found by other processes. |
399 allocator->MakeIterable(mem_reference); | 398 allocator->MakeIterable(mem_reference); |
400 | 399 |
401 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); | 400 return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); |
402 } | 401 } |
403 | 402 |
404 const base::FilePath& debug_file_path() const { return debug_file_path_; } | 403 const base::FilePath& debug_file_path() const { return debug_file_path_; } |
405 | 404 |
406 private: | 405 protected: |
407 base::ScopedTempDir temp_dir_; | 406 base::ScopedTempDir temp_dir_; |
408 base::FilePath debug_file_path_; | 407 base::FilePath debug_file_path_; |
| 408 |
| 409 std::unique_ptr<PersistentMemoryAllocator> allocator_; |
| 410 std::unique_ptr<ThreadActivityTracker> tracker_; |
409 }; | 411 }; |
410 | 412 |
411 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { | 413 TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) { |
| 414 // Create some activity data. |
| 415 tracker_->PushActivity(reinterpret_cast<void*>(kTaskOrigin), |
| 416 base::debug::Activity::ACT_TASK_RUN, |
| 417 ActivityData::ForTask(kTaskSequenceNum)); |
| 418 tracker_->PushActivity( |
| 419 nullptr, base::debug::Activity::ACT_LOCK_ACQUIRE, |
| 420 ActivityData::ForLock(reinterpret_cast<void*>(kLockAddress))); |
| 421 tracker_->PushActivity( |
| 422 nullptr, base::debug::Activity::ACT_EVENT_WAIT, |
| 423 ActivityData::ForEvent(reinterpret_cast<void*>(kEventAddress))); |
| 424 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN, |
| 425 ActivityData::ForThread(kThreadId)); |
| 426 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_PROCESS_WAIT, |
| 427 ActivityData::ForProcess(kProcessId)); |
| 428 // Note: this exceeds the activity stack's capacity. |
| 429 tracker_->PushActivity(nullptr, base::debug::Activity::ACT_THREAD_JOIN, |
| 430 ActivityData::ForThread(kAnotherThreadId)); |
| 431 |
412 // Validate collection returns the expected report. | 432 // Validate collection returns the expected report. |
413 PostmortemReportCollector collector(kProductName, kVersionNumber, | 433 PostmortemReportCollector collector(kProductName, kVersionNumber, |
414 kChannelName); | 434 kChannelName); |
415 std::unique_ptr<StabilityReport> report; | 435 std::unique_ptr<StabilityReport> report; |
416 ASSERT_EQ(PostmortemReportCollector::SUCCESS, | 436 ASSERT_EQ(PostmortemReportCollector::SUCCESS, |
417 collector.Collect(debug_file_path(), &report)); | 437 collector.Collect(debug_file_path(), &report)); |
418 ASSERT_NE(nullptr, report); | 438 ASSERT_NE(nullptr, report); |
419 | 439 |
420 // Build the expected report. | 440 // Validate the report. |
421 StabilityReport expected_report; | 441 ASSERT_EQ(1, report->process_states_size()); |
422 ProcessState* process_state = expected_report.add_process_states(); | 442 const ProcessState& process_state = report->process_states(0); |
423 ThreadState* thread_state = process_state->add_threads(); | 443 EXPECT_EQ(base::GetCurrentProcId(), process_state.process_id()); |
424 thread_state->set_thread_name(base::PlatformThread::GetName()); | 444 ASSERT_EQ(1, process_state.threads_size()); |
425 | 445 |
426 ASSERT_EQ(expected_report.SerializeAsString(), report->SerializeAsString()); | 446 const ThreadState& thread_state = process_state.threads(0); |
| 447 EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name()); |
| 448 #if defined(OS_WIN) |
| 449 EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id()); |
| 450 #elif defined(OS_POSIX) |
| 451 EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(), |
| 452 thread_state.thread_id()); |
| 453 #endif |
| 454 |
| 455 EXPECT_EQ(6, thread_state.activity_count()); |
| 456 ASSERT_EQ(5, thread_state.activities_size()); |
| 457 { |
| 458 const Activity& activity = thread_state.activities(0); |
| 459 EXPECT_EQ(Activity::ACT_TASK_RUN, activity.type()); |
| 460 EXPECT_EQ(kTaskOrigin, activity.origin_address()); |
| 461 EXPECT_EQ(kTaskSequenceNum, activity.task_sequence_id()); |
| 462 } |
| 463 { |
| 464 const Activity& activity = thread_state.activities(1); |
| 465 EXPECT_EQ(Activity::ACT_LOCK_ACQUIRE, activity.type()); |
| 466 EXPECT_EQ(kLockAddress, activity.lock_address()); |
| 467 } |
| 468 { |
| 469 const Activity& activity = thread_state.activities(2); |
| 470 EXPECT_EQ(Activity::ACT_EVENT_WAIT, activity.type()); |
| 471 EXPECT_EQ(kEventAddress, activity.event_address()); |
| 472 } |
| 473 { |
| 474 const Activity& activity = thread_state.activities(3); |
| 475 EXPECT_EQ(Activity::ACT_THREAD_JOIN, activity.type()); |
| 476 EXPECT_EQ(kThreadId, activity.thread_id()); |
| 477 } |
| 478 { |
| 479 const Activity& activity = thread_state.activities(4); |
| 480 EXPECT_EQ(Activity::ACT_PROCESS_WAIT, activity.type()); |
| 481 EXPECT_EQ(kProcessId, activity.process_id()); |
| 482 } |
427 } | 483 } |
428 | 484 |
429 } // namespace browser_watcher | 485 } // namespace browser_watcher |
OLD | NEW |