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 "base/debug/activity_tracker.h" | 5 #include "base/debug/activity_tracker.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/files/file.h" | 10 #include "base/files/file.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 if (!global_tracker) | 77 if (!global_tracker) |
78 return 0; | 78 return 0; |
79 base::AutoLock autolock(global_tracker->thread_tracker_allocator_lock_); | 79 base::AutoLock autolock(global_tracker->thread_tracker_allocator_lock_); |
80 return global_tracker->thread_tracker_allocator_.cache_used(); | 80 return global_tracker->thread_tracker_allocator_.cache_used(); |
81 } | 81 } |
82 | 82 |
83 size_t GetGlobalUserDataMemoryCacheUsed() { | 83 size_t GetGlobalUserDataMemoryCacheUsed() { |
84 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); | 84 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); |
85 } | 85 } |
86 | 86 |
| 87 void HandleProcessExit(int64_t id, |
| 88 int64_t stamp, |
| 89 int code, |
| 90 GlobalActivityTracker::ProcessPhase phase, |
| 91 std::string&& command, |
| 92 ActivityUserData::Snapshot&& data) { |
| 93 exit_id = id; |
| 94 exit_stamp = stamp; |
| 95 exit_code = code; |
| 96 exit_phase = phase; |
| 97 exit_command = std::move(command); |
| 98 exit_data = std::move(data); |
| 99 } |
| 100 |
87 static void DoNothing() {} | 101 static void DoNothing() {} |
| 102 |
| 103 int64_t exit_id = 0; |
| 104 int64_t exit_stamp; |
| 105 int exit_code; |
| 106 GlobalActivityTracker::ProcessPhase exit_phase; |
| 107 std::string exit_command; |
| 108 ActivityUserData::Snapshot exit_data; |
88 }; | 109 }; |
89 | 110 |
90 TEST_F(ActivityTrackerTest, UserDataTest) { | 111 TEST_F(ActivityTrackerTest, UserDataTest) { |
91 char buffer[256]; | 112 char buffer[256]; |
92 memset(buffer, 0, sizeof(buffer)); | 113 memset(buffer, 0, sizeof(buffer)); |
93 ActivityUserData data(buffer, sizeof(buffer)); | 114 ActivityUserData data(buffer, sizeof(buffer)); |
94 const size_t space = sizeof(buffer) - 8; | 115 size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader); |
95 ASSERT_EQ(space, data.available_); | 116 ASSERT_EQ(space, data.available_); |
96 | 117 |
97 data.SetInt("foo", 1); | 118 data.SetInt("foo", 1); |
98 ASSERT_EQ(space - 24, data.available_); | 119 space -= 24; |
| 120 ASSERT_EQ(space, data.available_); |
99 | 121 |
100 data.SetUint("b", 1U); // Small names fit beside header in a word. | 122 data.SetUint("b", 1U); // Small names fit beside header in a word. |
101 ASSERT_EQ(space - 24 - 16, data.available_); | 123 space -= 16; |
| 124 ASSERT_EQ(space, data.available_); |
102 | 125 |
103 data.Set("c", buffer, 10); | 126 data.Set("c", buffer, 10); |
104 ASSERT_EQ(space - 24 - 16 - 24, data.available_); | 127 space -= 24; |
| 128 ASSERT_EQ(space, data.available_); |
105 | 129 |
106 data.SetString("dear john", "it's been fun"); | 130 data.SetString("dear john", "it's been fun"); |
107 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); | 131 space -= 32; |
| 132 ASSERT_EQ(space, data.available_); |
108 | 133 |
109 data.Set("c", buffer, 20); | 134 data.Set("c", buffer, 20); |
110 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); | 135 ASSERT_EQ(space, data.available_); |
111 | 136 |
112 data.SetString("dear john", "but we're done together"); | 137 data.SetString("dear john", "but we're done together"); |
113 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); | 138 ASSERT_EQ(space, data.available_); |
114 | 139 |
115 data.SetString("dear john", "bye"); | 140 data.SetString("dear john", "bye"); |
116 ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); | 141 ASSERT_EQ(space, data.available_); |
117 | 142 |
118 data.SetChar("d", 'x'); | 143 data.SetChar("d", 'x'); |
119 ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8, data.available_); | 144 space -= 8; |
| 145 ASSERT_EQ(space, data.available_); |
120 | 146 |
121 data.SetBool("ee", true); | 147 data.SetBool("ee", true); |
122 ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16, data.available_); | 148 space -= 16; |
| 149 ASSERT_EQ(space, data.available_); |
123 | 150 |
124 data.SetString("f", ""); | 151 data.SetString("f", ""); |
125 ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16 - 8, data.available_); | 152 space -= 8; |
| 153 ASSERT_EQ(space, data.available_); |
126 } | 154 } |
127 | 155 |
128 TEST_F(ActivityTrackerTest, PushPopTest) { | 156 TEST_F(ActivityTrackerTest, PushPopTest) { |
129 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); | 157 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); |
130 ThreadActivityTracker::Snapshot snapshot; | 158 ThreadActivityTracker::Snapshot snapshot; |
131 | 159 |
132 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); | 160 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
133 ASSERT_EQ(0U, snapshot.activity_stack_depth); | 161 ASSERT_EQ(0U, snapshot.activity_stack_depth); |
134 ASSERT_EQ(0U, snapshot.activity_stack.size()); | 162 ASSERT_EQ(0U, snapshot.activity_stack.size()); |
135 | 163 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); | 271 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); |
244 global = GlobalActivityTracker::Get(); | 272 global = GlobalActivityTracker::Get(); |
245 EXPECT_EQ(std::string("bar"), global->allocator()->Name()); | 273 EXPECT_EQ(std::string("bar"), global->allocator()->Name()); |
246 global->ReleaseTrackerForCurrentThreadForTesting(); | 274 global->ReleaseTrackerForCurrentThreadForTesting(); |
247 delete global; | 275 delete global; |
248 } | 276 } |
249 | 277 |
250 | 278 |
251 // GlobalActivityTracker tests below. | 279 // GlobalActivityTracker tests below. |
252 | 280 |
| 281 TEST_F(ActivityTrackerTest, BasicTest) { |
| 282 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); |
| 283 GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 284 |
| 285 // Ensure the data repositories have backing store, indicated by non-zero ID. |
| 286 EXPECT_NE(0U, global->process_data().id()); |
| 287 EXPECT_NE(0U, global->global_data().id()); |
| 288 EXPECT_NE(global->process_data().id(), global->global_data().id()); |
| 289 } |
| 290 |
253 class SimpleActivityThread : public SimpleThread { | 291 class SimpleActivityThread : public SimpleThread { |
254 public: | 292 public: |
255 SimpleActivityThread(const std::string& name, | 293 SimpleActivityThread(const std::string& name, |
256 const void* origin, | 294 const void* origin, |
257 Activity::Type activity, | 295 Activity::Type activity, |
258 const ActivityData& data) | 296 const ActivityData& data) |
259 : SimpleThread(name, Options()), | 297 : SimpleThread(name, Options()), |
260 origin_(origin), | 298 origin_(origin), |
261 activity_(activity), | 299 activity_(activity), |
262 data_(data), | 300 data_(data), |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 t2.WaitReady(); | 367 t2.WaitReady(); |
330 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); | 368 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); |
331 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); | 369 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); |
332 | 370 |
333 t2.Exit(); | 371 t2.Exit(); |
334 t2.Join(); | 372 t2.Join(); |
335 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); | 373 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); |
336 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); | 374 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); |
337 } | 375 } |
338 | 376 |
| 377 TEST_F(ActivityTrackerTest, ProcessDeathTest) { |
| 378 // This doesn't actually create and destroy a process. Instead, it uses for- |
| 379 // testing interfaces to simulate data created by other processes. |
| 380 const ProcessId other_process_id = GetCurrentProcId() + 1; |
| 381 |
| 382 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); |
| 383 GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 384 ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); |
| 385 |
| 386 // Get callbacks for process exit. |
| 387 global->SetProcessExitCallback( |
| 388 Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this))); |
| 389 |
| 390 // Pretend than another process has started. |
| 391 global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar")); |
| 392 |
| 393 // Do some activities. |
| 394 PendingTask task(FROM_HERE, base::Bind(&DoNothing)); |
| 395 ScopedTaskRunActivity activity(task); |
| 396 ActivityUserData& user_data = activity.user_data(); |
| 397 ASSERT_NE(0U, user_data.id()); |
| 398 |
| 399 // Get the memory-allocator references to that data. |
| 400 PersistentMemoryAllocator::Reference proc_data_ref = |
| 401 global->allocator()->GetAsReference( |
| 402 global->process_data().GetBaseAddress(), |
| 403 GlobalActivityTracker::kTypeIdProcessDataRecord); |
| 404 ASSERT_TRUE(proc_data_ref); |
| 405 PersistentMemoryAllocator::Reference tracker_ref = |
| 406 global->allocator()->GetAsReference( |
| 407 thread->GetBaseAddress(), |
| 408 GlobalActivityTracker::kTypeIdActivityTracker); |
| 409 ASSERT_TRUE(tracker_ref); |
| 410 PersistentMemoryAllocator::Reference user_data_ref = |
| 411 global->allocator()->GetAsReference( |
| 412 user_data.GetBaseAddress(), |
| 413 GlobalActivityTracker::kTypeIdUserDataRecord); |
| 414 ASSERT_TRUE(user_data_ref); |
| 415 |
| 416 // Make a copy of the thread-tracker state so it can be restored later. |
| 417 const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref); |
| 418 std::unique_ptr<char[]> tracker_copy(new char[tracker_size]); |
| 419 memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); |
| 420 |
| 421 // Change the objects to appear to be owned by another process. |
| 422 ProcessId owning_id; |
| 423 int64_t stamp; |
| 424 ASSERT_TRUE(ActivityUserData::GetOwningProcessId( |
| 425 global->process_data().GetBaseAddress(), &owning_id, &stamp)); |
| 426 EXPECT_NE(other_process_id, owning_id); |
| 427 ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( |
| 428 thread->GetBaseAddress(), &owning_id, &stamp)); |
| 429 EXPECT_NE(other_process_id, owning_id); |
| 430 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), |
| 431 &owning_id, &stamp)); |
| 432 EXPECT_NE(other_process_id, owning_id); |
| 433 global->process_data().SetOwningProcessIdForTesting(other_process_id, stamp); |
| 434 thread->SetOwningProcessIdForTesting(other_process_id, stamp); |
| 435 user_data.SetOwningProcessIdForTesting(other_process_id, stamp); |
| 436 ASSERT_TRUE(ActivityUserData::GetOwningProcessId( |
| 437 global->process_data().GetBaseAddress(), &owning_id, &stamp)); |
| 438 EXPECT_EQ(other_process_id, owning_id); |
| 439 ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( |
| 440 thread->GetBaseAddress(), &owning_id, &stamp)); |
| 441 EXPECT_EQ(other_process_id, owning_id); |
| 442 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), |
| 443 &owning_id, &stamp)); |
| 444 EXPECT_EQ(other_process_id, owning_id); |
| 445 |
| 446 // Check that process exit will perform callback and free the allocations. |
| 447 ASSERT_EQ(0, exit_id); |
| 448 ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord, |
| 449 global->allocator()->GetType(proc_data_ref)); |
| 450 ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker, |
| 451 global->allocator()->GetType(tracker_ref)); |
| 452 ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord, |
| 453 global->allocator()->GetType(user_data_ref)); |
| 454 global->RecordProcessExit(other_process_id, 0); |
| 455 EXPECT_EQ(other_process_id, exit_id); |
| 456 EXPECT_EQ("foo --bar", exit_command); |
| 457 EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree, |
| 458 global->allocator()->GetType(proc_data_ref)); |
| 459 EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree, |
| 460 global->allocator()->GetType(tracker_ref)); |
| 461 EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree, |
| 462 global->allocator()->GetType(user_data_ref)); |
| 463 |
| 464 // Restore memory contents and types so things don't crash when doing real |
| 465 // process clean-up. |
| 466 memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(), |
| 467 tracker_size); |
| 468 global->allocator()->ChangeType( |
| 469 proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord, |
| 470 GlobalActivityTracker::kTypeIdUserDataRecordFree, false); |
| 471 global->allocator()->ChangeType( |
| 472 tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, |
| 473 GlobalActivityTracker::kTypeIdActivityTrackerFree, false); |
| 474 global->allocator()->ChangeType( |
| 475 user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord, |
| 476 GlobalActivityTracker::kTypeIdUserDataRecordFree, false); |
| 477 } |
| 478 |
339 } // namespace debug | 479 } // namespace debug |
340 } // namespace base | 480 } // namespace base |
OLD | NEW |