summaryrefslogtreecommitdiff
path: root/base/debug/activity_tracker_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/debug/activity_tracker_unittest.cc')
-rw-r--r--base/debug/activity_tracker_unittest.cc184
1 files changed, 173 insertions, 11 deletions
diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc
index aced4fb36a..116c13d623 100644
--- a/base/debug/activity_tracker_unittest.cc
+++ b/base/debug/activity_tracker_unittest.cc
@@ -84,45 +84,73 @@ 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));
- const size_t space = sizeof(buffer) - 8;
+ size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader);
ASSERT_EQ(space, data.available_);
data.SetInt("foo", 1);
- ASSERT_EQ(space - 24, data.available_);
+ space -= 24;
+ ASSERT_EQ(space, data.available_);
data.SetUint("b", 1U); // Small names fit beside header in a word.
- ASSERT_EQ(space - 24 - 16, data.available_);
+ space -= 16;
+ ASSERT_EQ(space, data.available_);
data.Set("c", buffer, 10);
- ASSERT_EQ(space - 24 - 16 - 24, data.available_);
+ space -= 24;
+ ASSERT_EQ(space, data.available_);
data.SetString("dear john", "it's been fun");
- ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_);
+ space -= 32;
+ ASSERT_EQ(space, data.available_);
data.Set("c", buffer, 20);
- ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_);
+ ASSERT_EQ(space, data.available_);
data.SetString("dear john", "but we're done together");
- ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_);
+ ASSERT_EQ(space, data.available_);
data.SetString("dear john", "bye");
- ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_);
+ ASSERT_EQ(space, data.available_);
data.SetChar("d", 'x');
- ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8, data.available_);
+ space -= 8;
+ ASSERT_EQ(space, data.available_);
data.SetBool("ee", true);
- ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16, data.available_);
+ space -= 16;
+ ASSERT_EQ(space, data.available_);
data.SetString("f", "");
- ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16 - 8, data.available_);
+ space -= 8;
+ ASSERT_EQ(space, data.available_);
}
TEST_F(ActivityTrackerTest, PushPopTest) {
@@ -222,6 +250,28 @@ TEST_F(ActivityTrackerTest, ScopedTaskTest) {
ASSERT_EQ(2U, GetGlobalUserDataMemoryCacheUsed());
}
+TEST_F(ActivityTrackerTest, ExceptionTest) {
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
+ GlobalActivityTracker* global = GlobalActivityTracker::Get();
+
+ ThreadActivityTracker* tracker =
+ GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
+ ThreadActivityTracker::Snapshot snapshot;
+ ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
+
+ ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
+ ASSERT_EQ(0U, snapshot.last_exception.activity_type);
+
+ char origin;
+ global->RecordException(&origin, 42);
+
+ ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
+ EXPECT_EQ(Activity::ACT_EXCEPTION, snapshot.last_exception.activity_type);
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin),
+ snapshot.last_exception.origin_address);
+ EXPECT_EQ(42U, snapshot.last_exception.data.exception.code);
+}
+
TEST_F(ActivityTrackerTest, CreateWithFileTest) {
const char temp_name[] = "CreateWithFileTest";
ScopedTempDir temp_dir;
@@ -250,6 +300,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,
@@ -336,5 +396,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