| 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 |