| Index: base/debug/activity_tracker_unittest.cc
|
| diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc
|
| index c46b81686b9147abc18266e0ac7dbc3166075688..d57c898975cb88fefa17124fe3ef9166f8a641d4 100644
|
| --- a/base/debug/activity_tracker_unittest.cc
|
| +++ b/base/debug/activity_tracker_unittest.cc
|
| @@ -84,41 +84,69 @@ class ActivityTrackerTest : public testing::Test {
|
| return GlobalActivityTracker::Get()->user_data_allocator_.cache_used();
|
| }
|
|
|
| + void HandleProcessExit(int64_t id,
|
| + int64_t stamp,
|
| + int code,
|
| + GlobalActivityTracker::ProcessPhase phase,
|
| + std::string&& command,
|
| + ActivityUserData::Snapshot&& data) {
|
| + exit_id = id;
|
| + exit_stamp = stamp;
|
| + exit_code = code;
|
| + exit_phase = phase;
|
| + exit_command = std::move(command);
|
| + exit_data = std::move(data);
|
| + }
|
| +
|
| static void DoNothing() {}
|
| +
|
| + int64_t exit_id = 0;
|
| + int64_t exit_stamp;
|
| + int exit_code;
|
| + GlobalActivityTracker::ProcessPhase exit_phase;
|
| + std::string exit_command;
|
| + ActivityUserData::Snapshot exit_data;
|
| };
|
|
|
| TEST_F(ActivityTrackerTest, UserDataTest) {
|
| char buffer[256];
|
| memset(buffer, 0, sizeof(buffer));
|
| ActivityUserData data(buffer, sizeof(buffer));
|
| - ASSERT_EQ(sizeof(buffer) - 8, data.available_);
|
| + size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader);
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetInt("foo", 1);
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24, data.available_);
|
| + space -= 24;
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetUint("b", 1U); // Small names fit beside header in a word.
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16, data.available_);
|
| + space -= 16;
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.Set("c", buffer, 10);
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24, data.available_);
|
| + space -= 24;
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetString("dear john", "it's been fun");
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_);
|
| + space -= 32;
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.Set("c", buffer, 20);
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_);
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetString("dear john", "but we're done together");
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_);
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetString("dear john", "bye");
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_);
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetChar("d", 'x');
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32 - 8, data.available_);
|
| + space -= 8;
|
| + ASSERT_EQ(space, data.available_);
|
|
|
| data.SetBool("ee", true);
|
| - ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32 - 8 - 16, data.available_);
|
| + space -= 16;
|
| + ASSERT_EQ(space, data.available_);
|
| }
|
|
|
| TEST_F(ActivityTrackerTest, PushPopTest) {
|
| @@ -246,6 +274,16 @@ TEST_F(ActivityTrackerTest, CreateWithFileTest) {
|
|
|
| // GlobalActivityTracker tests below.
|
|
|
| +TEST_F(ActivityTrackerTest, BasicTest) {
|
| + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
|
| + GlobalActivityTracker* global = GlobalActivityTracker::Get();
|
| +
|
| + // Ensure the data repositories have backing store, indicated by non-zero ID.
|
| + EXPECT_NE(0U, global->process_data().id());
|
| + EXPECT_NE(0U, global->global_data().id());
|
| + EXPECT_NE(global->process_data().id(), global->global_data().id());
|
| +}
|
| +
|
| class SimpleActivityThread : public SimpleThread {
|
| public:
|
| SimpleActivityThread(const std::string& name,
|
| @@ -332,5 +370,107 @@ TEST_F(ActivityTrackerTest, ThreadDeathTest) {
|
| EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
|
| }
|
|
|
| +TEST_F(ActivityTrackerTest, ProcessDeathTest) {
|
| + // This doesn't actually create and destroy a process. Instead, it uses for-
|
| + // testing interfaces to simulate data created by other processes.
|
| + const ProcessId other_process_id = GetCurrentProcId() + 1;
|
| +
|
| + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
|
| + GlobalActivityTracker* global = GlobalActivityTracker::Get();
|
| + ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread();
|
| +
|
| + // Get callbacks for process exit.
|
| + global->SetProcessExitCallback(
|
| + Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this)));
|
| +
|
| + // Pretend than another process has started.
|
| + global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar"));
|
| +
|
| + // Do some activities.
|
| + PendingTask task(FROM_HERE, base::Bind(&DoNothing));
|
| + ScopedTaskRunActivity activity(task);
|
| + ActivityUserData& user_data = activity.user_data();
|
| + ASSERT_NE(0U, user_data.id());
|
| +
|
| + // Get the memory-allocator references to that data.
|
| + PersistentMemoryAllocator::Reference proc_data_ref =
|
| + global->allocator()->GetAsReference(
|
| + global->process_data().GetBaseAddress(),
|
| + GlobalActivityTracker::kTypeIdProcessDataRecord);
|
| + ASSERT_TRUE(proc_data_ref);
|
| + PersistentMemoryAllocator::Reference tracker_ref =
|
| + global->allocator()->GetAsReference(
|
| + thread->GetBaseAddress(),
|
| + GlobalActivityTracker::kTypeIdActivityTracker);
|
| + ASSERT_TRUE(tracker_ref);
|
| + PersistentMemoryAllocator::Reference user_data_ref =
|
| + global->allocator()->GetAsReference(
|
| + user_data.GetBaseAddress(),
|
| + GlobalActivityTracker::kTypeIdUserDataRecord);
|
| + ASSERT_TRUE(user_data_ref);
|
| +
|
| + // Make a copy of the thread-tracker state so it can be restored later.
|
| + const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref);
|
| + std::unique_ptr<char[]> tracker_copy(new char[tracker_size]);
|
| + memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size);
|
| +
|
| + // Change the objects to appear to be owned by another process.
|
| + ProcessId owning_id;
|
| + int64_t stamp;
|
| + ASSERT_TRUE(ActivityUserData::GetOwningProcessId(
|
| + global->process_data().GetBaseAddress(), &owning_id, &stamp));
|
| + EXPECT_NE(other_process_id, owning_id);
|
| + ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId(
|
| + thread->GetBaseAddress(), &owning_id, &stamp));
|
| + EXPECT_NE(other_process_id, owning_id);
|
| + ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(),
|
| + &owning_id, &stamp));
|
| + EXPECT_NE(other_process_id, owning_id);
|
| + global->process_data().SetOwningProcessIdForTesting(other_process_id, stamp);
|
| + thread->SetOwningProcessIdForTesting(other_process_id, stamp);
|
| + user_data.SetOwningProcessIdForTesting(other_process_id, stamp);
|
| + ASSERT_TRUE(ActivityUserData::GetOwningProcessId(
|
| + global->process_data().GetBaseAddress(), &owning_id, &stamp));
|
| + EXPECT_EQ(other_process_id, owning_id);
|
| + ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId(
|
| + thread->GetBaseAddress(), &owning_id, &stamp));
|
| + EXPECT_EQ(other_process_id, owning_id);
|
| + ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(),
|
| + &owning_id, &stamp));
|
| + EXPECT_EQ(other_process_id, owning_id);
|
| +
|
| + // Check that process exit will perform callback and free the allocations.
|
| + ASSERT_EQ(0, exit_id);
|
| + ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord,
|
| + global->allocator()->GetType(proc_data_ref));
|
| + ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker,
|
| + global->allocator()->GetType(tracker_ref));
|
| + ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord,
|
| + global->allocator()->GetType(user_data_ref));
|
| + global->RecordProcessExit(other_process_id, 0);
|
| + EXPECT_EQ(other_process_id, exit_id);
|
| + EXPECT_EQ("foo --bar", exit_command);
|
| + EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree,
|
| + global->allocator()->GetType(proc_data_ref));
|
| + EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree,
|
| + global->allocator()->GetType(tracker_ref));
|
| + EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree,
|
| + global->allocator()->GetType(user_data_ref));
|
| +
|
| + // Restore memory contents and types so things don't crash when doing real
|
| + // process clean-up.
|
| + memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(),
|
| + tracker_size);
|
| + global->allocator()->ChangeType(
|
| + proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord,
|
| + GlobalActivityTracker::kTypeIdUserDataRecordFree, false);
|
| + global->allocator()->ChangeType(
|
| + tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker,
|
| + GlobalActivityTracker::kTypeIdActivityTrackerFree, false);
|
| + global->allocator()->ChangeType(
|
| + user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord,
|
| + GlobalActivityTracker::kTypeIdUserDataRecordFree, false);
|
| +}
|
| +
|
| } // namespace debug
|
| } // namespace base
|
|
|